目录
1.1 __spi_validate(参数message检查)
1.2.1 ctlr->transfer == spi_queued_transfer(没有定义ctlr->transfer,同步传输)
1.2.2 spi_async_locked(定义ctlr->transfer)(异步传输)
2.1 如果设置ctlr->transfer则其不用设置,异步传输
2.3 transfer_one_message里面如果需要,设置spi->controller->set_cs
spi传输的核心函数是spi_sync,所有与spi控制器的读写操作都是使用这个函数,我们沿着这个函数分析,看看如何调用到spi master的,以及spi master需要实现的一些字段。spi_sync是同步传输,spi_async是异步传输。
spi_async
__spi_async
ctlr->transfer(spi_queued_transfer) // ctlr->transfer = spi_queued_transfer;
__spi_queued_transfer
spi_pump_messages
__spi_pump_messages
unprepare_transfer_hardware
prepare_transfer_hardware
prepare_message
ctlr->transfer_one_message(ctlr, ctlr->cur_msg);
spi_set_cs-->spi->controller->set_cs
ret = ctlr->transfer_one(ctlr, msg->spi, xfer);
spi_set_cs
1. spi_sync
spi_sync->__spi_sync
1.1 __spi_validate(参数message检查)
static int __spi_sync(struct spi_device *spi, struct spi_message *message)
{
.......
struct spi_controller *ctlr = spi->controller;
status = __spi_validate(spi, message);
if (status != 0)
return status;
.........
}
static int __spi_validate(struct spi_device *spi, struct spi_message *message)
{
struct spi_controller *ctlr = spi->controller;
struct spi_transfer *xfer;
int w_size;
if (list_empty(&message->transfers))
return -EINVAL;
/* Half-duplex links include original MicroWire, and ones with
* only one data pin like SPI_3WIRE (switches direction) or where
* either MOSI or MISO is missing. They can also be caused by
* software limitations.
*/
if ((ctlr->flags & SPI_CONTROLLER_HALF_DUPLEX) ||
(spi->mode & SPI_3WIRE)) {
unsigned flags = ctlr->flags;
list_for_each_entry(xfer, &message->transfers, transfer_list) {
if (xfer->rx_buf && xfer->tx_buf)
return -EINVAL;
if ((flags & SPI_CONTROLLER_NO_TX) && xfer->tx_buf)
return -EINVAL;
if ((flags & SPI_CONTROLLER_NO_RX) && xfer->rx_buf)
return -EINVAL;
}
}
/**
* Set transfer bits_per_word and max speed as spi device default if
* it is not set for this transfer.
* Set transfer tx_nbits and rx_nbits as single transfer default
* (SPI_NBITS_SINGLE) if it is not set for this transfer.
*/
message->frame_length = 0;
list_for_each_entry(xfer, &message->transfers, transfer_list) {
message->frame_length += xfer->len;
if (!xfer->bits_per_word)
xfer->bits_per_word = spi->bits_per_word;
if (!xfer->speed_hz)
xfer->speed_hz = spi->max_speed_hz;
if (!xfer->speed_hz)
xfer->speed_hz = ctlr->max_speed_hz;
if (ctlr->max_speed_hz && xfer->speed_hz > ctlr->max_speed_hz)
xfer->speed_hz = ctlr->max_speed_hz;
if (__spi_validate_bits_per_word(ctlr, xfer->bits_per_word))
return -EINVAL;
/*
* SPI transfer length should be multiple of SPI word size
* where SPI word size should be power-of-two multiple
*/
if (xfer->bits_per_word <= 8)
w_size = 1;
else if (xfer->bits_per_word <= 16)
w_size = 2;
else
w_size = 4;
/* No partial transfers accepted */
if (xfer->len % w_size)
return -EINVAL;
if (xfer->speed_hz && ctlr->min_speed_hz &&
xfer->speed_hz < ctlr->min_speed_hz)
return -EINVAL;
if (xfer->tx_buf && !xfer->tx_nbits)
xfer->tx_nbits = SPI_NBITS_SINGLE;
if (xfer->rx_buf && !xfer->rx_nbits)
xfer->rx_nbits = SPI_NBITS_SINGLE;
/* check transfer tx/rx_nbits:
* 1. check the value matches one of single, dual and quad
* 2. check tx/rx_nbits match the mode in spi_device
*/
if (xfer->tx_buf) {
if (xfer->tx_nbits != SPI_NBITS_SINGLE &&
xfer->tx_nbits != SPI_NBITS_DUAL &&
xfer->tx_nbits != SPI_NBITS_QUAD)
return -EINVAL;
if ((xfer->tx_nbits == SPI_NBITS_DUAL) &&
!(spi->mode & (SPI_TX_DUAL | SPI_TX_QUAD)))
return -EINVAL;
if ((xfer->tx_nbits == SPI_NBITS_QUAD) &&
!(spi->mode & SPI_TX_QUAD))
return -EINVAL;
}
/* check transfer rx_nbits */
if (xfer->rx_buf) {
if (xfer->rx_nbits != SPI_NBITS_SINGLE &&
xfer->rx_nbits != SPI_NBITS_DUAL &&
xfer->rx_nbits != SPI_NBITS_QUAD)
return -EINVAL;
if ((xfer->rx_nbits == SPI_NBITS_DUAL) &&
!(spi->mode & (SPI_RX_DUAL | SPI_RX_QUAD)))
return -EINVAL;
if ((xfer->rx_nbits == SPI_NBITS_QUAD) &&
!(spi->mode & SPI_RX_QUAD))
return -EINVAL;
}
}
message->status = -EINPROGRESS;
return 0;
}
这个主要是master、device、transfer的参数的检查。device的参数主要在spi_add_device->spi_setup中设置,详细见文章。
1.2 transfer选择
static int __spi_sync(struct spi_device *spi, struct spi_message *message)
{
......
/* If we're not using the legacy transfer method then we will
* try to transfer in the calling context so special case.
* This code would be less tricky if we could remove the
* support for driver implemented message queues.
*/
if (ctlr->transfer == spi_queued_transfer) {
spin_lock_irqsave(&ctlr->bus_lock_spinlock, flags);
trace_spi_message_submit(message);
status = __spi_queued_transfer(spi, message, false);
spin_unlock_irqrestore(&ctlr->bus_lock_spinlock, flags);
} else {
status = spi_async_locked(spi, message);
}
.........
}
1.2.1 ctlr->transfer == spi_queued_transfer(没有定义ctlr->transfer,同步传输)
在前面的文章中介绍过,如果没有定义ctlr->transfer的话,会调用spi_controller_initialize_queue函数,再这个函数里面会把ctlr->transfer = spi_queued_transfer。并且会调用spi_init_queue初始化queue。
static int spi_init_queue(struct spi_controller *ctlr)
{
.......
kthread_init_work(&ctlr->pump_messages, spi_pump_messages);
......
return 0;
}
static int spi_controller_initialize_queue(struct spi_controller *ctlr)
{
.....
ctlr->transfer = spi_queued_transfer;
if (!ctlr->transfer_one_message)
ctlr->transfer_one_message = spi_transfer_one_message;
/* Initialize and start queue */
ret = spi_init_queue(ctlr);
.......
}
__spi_queued_transfer->kthread_queue_work(&ctlr->kworker, &ctlr->pump_messages)->spi_pump_messages->__spi_pump_messages
static void __spi_pump_messages(struct spi_controller *ctlr, bool in_kthread)
{
......
ctlr->unprepare_transfer_hardware(如果存在就执行)
ctlr->prepare_transfer_hardware(如果存在就执行)
ctlr->prepare_message(如果存在就执行)
ctlr->transfer_one_message(执行)
.....
}
ctlr->transfer_one_message如果存在就执行,如果没有定义,会在前面赋值为spi_transfer_one_message。
static int spi_transfer_one_message(struct spi_controller *ctlr,
struct spi_message *msg)
{
......
spi_set_cs(msg->spi, true);
......
list_for_each_entry(xfer, &msg->transfers, transfer_list) {
............
ret = ctlr->transfer_one(ctlr, msg->spi, xfer);
......
}
......
spi_set_cs(msg->spi, false);
......
}
1.2.2 spi_async_locked(定义ctlr->transfer)(异步传输)
spi_async_locked->__spi_async->ctlr->transfer(spi, message)。执行自己定义的transfer。
1.3 等待传输完成
static int __spi_sync(struct spi_device *spi, struct spi_message *message)
{
if (status == 0) {
......
wait_for_completion(&done);
status = message->status;
}
message->context = NULL;
return status;
}
2. ctrl要实现的一些函数字段
2.1 如果设置ctlr->transfer则其不用设置,异步传输
实现ctlr->transfer
2.2 如果ctlr->transfer没有设置,同步传输
ctlr->unprepare_transfer_hardware(如果存在就执行)
ctlr->prepare_transfer_hardware(如果存在就执行)
ctlr->prepare_message(如果存在就执行)
ctlr->transfer_one_message(如果存在执行,如果不存在实现ctlr->transfer_one)