协议介绍
SPI(Serial Peripheral Interface),即串行外设接口,是一种串口通信接口协议。SPI遵循主从模式框架设计架构,但只能有一个主设备。SPI总线有4条信号线,CS(片选信号线),SCLK(时钟信号线),MOSI(主出从入信号线)和MISO(主入从出信号线),因此SPI是全双工总线。SPI的工作原理比较简单,主设备控制片选和时钟输出,输出数据到从设备及读取从设备输入的数据。
SPI协议有四种时钟工作模式(Mode0,Mode1,Mode2和Mode3),要求主从设备工作模式一致。从设备在出厂之后,时钟工作模式已经固定,一般通过修改主设备的时钟工作模式来匹配从设备时钟模式。SPI的四种工作模式取决于时钟极性(CPOL)和时钟相位(CPHA)的组合,时钟极性CPOL用来配置SCLK的电平处于哪种状态时是空闲态或者工作态,而时钟相位CPHA用来配置数据采样在哪个时钟沿:
(1)CPOL=0,表示SCLK低电平时是空闲态,也就是SCLK高电平时是工作态
(2)CPOL=1,表示SCLK高电平时是工作态,也就是SCLK低电平时是工作态
(3)CPHA=0,表示数据采样在第一个时钟沿,数据发送在第二个时钟沿
(4)CPHA=1,表示数据采样在第二个时钟沿,数据发送在第一个时钟沿
协议工作时序图如下(图片来源于网络):
SPI总线具有传输速率快,全双工和硬件电路简单等有点,但是有个缺点:没有类似于I2C总线的应答机制。
内核框架
内核中SPI总线协议框架类似于I2C的总线框架。核心层提供spi_master,spi_device,spi_driver,spi_message和spi_transfer核心数据结构和API接口,供上层系统注册主设备驱动,从设备以及从设备驱动。
1,数据结构:
(1)struct spi_master:主设备和驱动。spi_master结构包含主设备速率,工作模式,统计相关信息。采用了kernel workqueue的工作模式,提供了数据传输相关的回调接口:transfer()接口用于将spi_message加入消息队列,workqueue从消息队列中取出spi_message,通过transfer_one_message()接口发送一个spi_message,每个spi_message包含多个spi_transfer,最终通过transfer_one()接口发送一个spi_transfer。
struct spi_master {
struct device dev;struct list_head list;
/* other than negative (== assign one dynamically), bus_num is fully
* board-specific. usually that simplifies to being SOC-specific. * example: one SOC has three SPI controllers, numbered 0..2, * and one board's schematics might show it using SPI-2. software * would normally use bus_num=2 for that controller. */ s16 bus_num; // 总线编号/* chipselects will be integral to many controllers; some others
* might use board-specific GPIOs. */ u16 num_chipselect; // 片选个数/* some SPI controllers pose alignment requirements on DMAable
* buffers; let protocol drivers know about these requirements. */ u16 dma_alignment;/* spi_device.mode flags understood by this controller driver */
u16 mode_bits;/* bitmask of supported bits_per_word for transfers */
u32 bits_per_word_mask; // 一个transfer的bit数掩码 #define SPI_BPW_MASK(bits) BIT((bits) - 1) #define SPI_BIT_MASK(bits) (((bits) == 32) ? ~0U : (BIT(bits) - 1)) #define SPI_BPW_RANGE_MASK(min, max) (SPI_BIT_MASK(max) - SPI_BIT_MASK(min - 1))/* limits on transfer speed */
u32 min_speed_hz; // 支持的最小传输速率 u32 max_speed_hz; // 支持的最大传输速率/* other constraints relevant to this driver */
u16 flags; #define SPI_MASTER_HALF_DUPLEX BIT(0) /* can't do full duplex */ #define SPI_MASTER_NO_RX BIT(1) /* can't do buffer read */ #define SPI_MASTER_NO_TX BIT(2) /* can't do buffer write */ #define SPI_MASTER_MUST_RX BIT(3) /* requires rx */ #define SPI_MASTER_MUST_TX BIT(4) /* requires tx *//* lock and mutex for SPI bus locking */
spinlock_t bus_lock_spinlock; struct mutex bus_lock_mutex;/* flag indicating that the SPI bus is locked for exclusive use */
bool bus_lock_flag;/* Setup mode and clock, etc (spi driver may call many times).
* * IMPORTANT: this may be called when transfers to another * device are active. DO NOT UPDATE SHARED REGISTERS in ways * which could break those transfers. */ int (*setup)(struct spi_device *spi); // 每个transfer传输之前由 spi_driver调用,用于配置传输参数(不同从设备在速率和时钟模式上都可能不同,因此每个transfer都需要重新配置)/* bidirectional bulk transfers
* * + The transfer() method may not sleep; its main role is * just to add the message to the queue. * + For now there's no remove-from-queue operation, or * any other request management * + To a given spi_device, message queueing is pure fifo * * + The master's main job is to process its message queue, * selecting a chip then transferring data * + If there are multiple spi_device children, the i/o queue * arbitration algorithm is unspecified (round robin, fifo, * priority, reservations, preemption, etc) * * + Chipselect stays active during the entire message * (unless modified by spi_transfer.cs_change != 0). * + The message transfers use clock and SPI mode parameters * previously established by setup() for this device */ int (*transfer)(struct spi_device *spi, struct spi_message *mesg); // spi_async() / spi_sync() 接口调用该方法将spi_message消息加入队列/* called on release() to free memory provided by spi_master */
void (*cleanup)(struct spi_device *spi);/*
* Used to enable core support for DMA handling, if can_dma() * exists and returns true then the transfer will be mapped * prior to transfer_one() being called. The driver should * not modify or store xfer and dma_tx and dma_rx must be set * while the device is prepared. */ bool (*can_dma)(struct spi_master *master, struct spi_device *spi, struct spi_transfer *xfer);/*
* These hooks are for drivers that want to use the generic * master transfer queueing mechanism. If these are used, the * transfer() function above must NOT be specified by the driver. * Over time we expect SPI drivers to be phased over to this API. */ bool queued; struct kthread_worker kworker; struct task_struct *kworker_task; struct kthread_work pump_messages; // work queue,用于处理队列中的spi_message spinlock_t queue_lock; struct list_head queue; struct spi_message *cur_msg; bool idling; bool busy; bool running; bool rt; bool auto_runtime_pm; bool cur_msg_prepared; bool cur_msg_mapped; struct completion xfer_completion; size_t max_dma_len;int (*prepare_transfer_hardware)(struct spi_master *master); // 准备好硬件,用于实际数据传输
int (*transfer_one_message)(struct spi_master *master, struct spi_message *mesg); // 发送一个spi_message int (*unprepare_transfer_hardware)(struct spi_master *master); int (*prepare_message)(struct spi_master *master, struct spi_message *message); int (*unprepare_message)(struct spi_master *master, struct spi_message *message);/*
* These hooks are for drivers that use a generic implementation * of transfer_one_message() provied by the core. */ void (*set_cs)(struct spi_device *spi, bool enable); // 每次传输前,设置片选信号 int (*transfer_one)(struct spi_master *master, struct spi_device *spi, struct spi_transfer *transfer); // 发送一个 spi_transfer void (*handle_err)(struct spi_master *master, struct spi_message *message);/* gpio chip select */
int *cs_gpios;/* statistics */
struct spi_statistics statistics;/* DMA channels for use with core dmaengine helpers */
struct dma_chan *dma_tx; struct dma_chan *dma_rx;/* dummy data for full duplex devices */
void *dummy_rx; void *dummy_tx; }; (2)struct spi_device:spi_device用于描述一个spi从设备,一般在主设备注册时,通过平台相关代码配置或者设备树配置自动创建并注册。struct spi_device {
struct device dev; struct spi_master *master; u32 max_speed_hz; // 支持的最大传输速率 u8 chip_select; // 片选 u8 bits_per_word; // 单位传输bit数 u16 mode; // 工作模式 #define SPI_CPHA 0x01 /* clock phase */ #define SPI_CPOL 0x02 /* clock polarity */ #define SPI_MODE_0 (0|0) /* (original MicroWire) */ #define SPI_MODE_1 (0|SPI_CPHA) #define SPI_MODE_2 (SPI_CPOL|0) #define SPI_MODE_3 (SPI_CPOL|SPI_CPHA) #define SPI_CS_HIGH 0x04 /* chipselect active high? */ #define SPI_LSB_FIRST 0x08 /* per-word bits-on-wire */ #define SPI_3WIRE 0x10 /* SI/SO signals shared */ #define SPI_LOOP 0x20 /* loopback mode */ #define SPI_NO_CS 0x40 /* 1 dev/bus, no chipselect */ #define SPI_READY 0x80 /* slave pulls low to pause */ #define SPI_TX_DUAL 0x100 /* transmit with 2 wires */ #define SPI_TX_QUAD 0x200 /* transmit with 4 wires */ #define SPI_RX_DUAL 0x400 /* receive with 2 wires */ #define SPI_RX_QUAD 0x800 /* receive with 4 wires */ int irq; void *controller_state; void *controller_data; char modalias[SPI_NAME_SIZE]; int cs_gpio; /* chip select gpio *//* the statistics */
struct spi_statistics statistics;/*
* likely need more hooks for more protocol options affecting how * the controller talks to each chip, like: * - memory packing (12 bit samples into low bits, others zeroed) * - priority * - drop chipselect after each word * - chipselect delays * - ... */ };(3)struct spi_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); struct device_driver driver; }; (4)struct spi_message:spi消息结构struct spi_message {
struct list_head transfers; // 包含的spi_transfer列表struct spi_device *spi;
unsigned is_dma_mapped:1;
/* REVISIT: we might want a flag affecting the behavior of the
* last transfer ... allowing things like "read 16 bit length L" * immediately followed by "read L bytes". Basically imposing * a specific message scheduling algorithm. * * Some controller drivers (message-at-a-time queue processing) * could provide that as their default scheduling algorithm. But * others (with multi-message pipelines) could need a flag to * tell them about such special cases. *//* completion is reported through a callback */
void (*complete)(void *context); void *context; unsigned frame_length; unsigned actual_length; int status;/* for optional use by whatever driver currently owns the
* spi_message ... between calls to spi_async and then later * complete(), that's the spi_master controller driver. */ struct list_head queue; void *state; }; (5)spi_transfer:包含在spi_message中的spi_transferstruct spi_transfer {
/* it's ok if tx_buf == rx_buf (right?) * for MicroWire, one buffer must be null * buffers must work with dma_*map_single() calls, unless * spi_message.is_dma_mapped reports a pre-existing mapping */ const void *tx_buf; // 发送buffer void *rx_buf; // 接收buffer unsigned len; // buffer长度dma_addr_t tx_dma;
dma_addr_t rx_dma; struct sg_table tx_sg; struct sg_table rx_sg;unsigned cs_change:1;
unsigned tx_nbits:3; unsigned rx_nbits:3; #define SPI_NBITS_SINGLE 0x01 /* 1bit transfer */ #define SPI_NBITS_DUAL 0x02 /* 2bits transfer */ #define SPI_NBITS_QUAD 0x04 /* 4bits transfer */ u8 bits_per_word; u16 delay_usecs; u32 speed_hz;struct list_head transfer_list;
}; 2,框架接口:(1)spi_master注册接口:int spi_register_master(struct spi_master *master);
int spi_register_master(struct spi_master *master)
{ static atomic_t dyn_bus_id = ATOMIC_INIT((1<<15) - 1); struct device *dev = master->dev.parent; struct boardinfo *bi; int status = -ENODEV; int dynamic = 0;if (!dev)
return -ENODEV;status = of_spi_register_master(master); // 从设备树配置中获取片选个数,和片选gpio编号
if (status) return status;/* even if it's just one always-selected device, there must
* be at least one chipselect */ if (master->num_chipselect == 0) return -EINVAL;if ((master->bus_num < 0) && master->dev.of_node)
master->bus_num = of_alias_get_id(master->dev.of_node, "spi");/* convention: dynamically assigned bus IDs count down from the max */
if (master->bus_num < 0) { /* FIXME switch to an IDR based scheme, something like * I2C now uses, so we can't run out of "dynamic" IDs */ master->bus_num = atomic_dec_return(&dyn_bus_id); dynamic = 1; }INIT_LIST_HEAD(&master->queue);
spin_lock_init(&master->queue_lock); spin_lock_init(&master->bus_lock_spinlock); mutex_init(&master->bus_lock_mutex); master->bus_lock_flag = 0; init_completion(&master->xfer_completion); if (!master->max_dma_len) master->max_dma_len = INT_MAX;/* register the device, then userspace will see it.
* registration fails if the bus ID is in use. */ dev_set_name(&master->dev, "spi%u", master->bus_num); status = device_add(&master->dev); // 注册master到kernel设备驱动框架 if (status < 0) goto done; dev_dbg(dev, "registered master %s%s\n", dev_name(&master->dev), dynamic ? " (dynamic)" : "");/* If we're using a queued driver, start the queue */
if (master->transfer) dev_info(dev, "master is unqueued, this is deprecated\n"); else { status = spi_master_initialize_queue(master); // 初始化主设备消息队列处理机制,workqueue if (status) { device_del(&master->dev); goto done; } } /* add statistics */ spin_lock_init(&master->statistics.lock);mutex_lock(&board_lock);
list_add_tail(&master->list, &spi_master_list); // 将master加入 spi_master_list 列表中 list_for_each_entry(bi, &board_list, list) spi_match_master_to_boardinfo(master, &bi->board_info); // 从预配置的board_list中创建匹配的spi_device mutex_unlock(&board_lock);/* Register devices from the device tree and ACPI */
of_register_spi_devices(master); // 从设备树配置中创建并注册所有的spi_device acpi_register_spi_devices(master); done: return status; }static int spi_master_initialize_queue(struct spi_master *master)
{ int ret;master->transfer = spi_queued_transfer; // 设置transfer方法为 spi_queued_transfer(),该方法将spi_message加入master的message queue
if (!master->transfer_one_message) master->transfer_one_message = spi_transfer_one_message; // spi_transfer_one_message用来轮询message中的所有spi_transfer,调 用 master中的transfer_one来一个个传输spi_transfer/* Initialize and start queue */
ret = spi_init_queue(master); // 初始化workqueue线程 if (ret) { dev_err(&master->dev, "problem initializing queue\n"); goto err_init_queue; } master->queued = true; ret = spi_start_queue(master); // 启动workqueue线程,执行spi_pump_messages()方法从消息队列获取spi_message进行传输 if (ret) { dev_err(&master->dev, "problem starting queue\n"); goto err_start_queue; }return 0;
err_start_queue:
spi_destroy_queue(master); err_init_queue: return ret; }static void of_register_spi_devices(struct spi_master *master)
{ struct spi_device *spi; struct device_node *nc;if (!master->dev.of_node)
return;for_each_available_child_of_node(master->dev.of_node, nc) {
spi = of_register_spi_device(master, nc); // 轮询注册每个spi_device if (IS_ERR(spi)) dev_warn(&master->dev, "Failed to create SPI device for %s\n", nc->full_name); } }of_register_spi_device(struct spi_master *master, struct device_node *nc)
{ struct spi_device *spi; int rc; u32 value;/* Alloc an spi_device */
spi = spi_alloc_device(master); // 分配spi_device结构 if (!spi) { dev_err(&master->dev, "spi_device alloc error for %s\n", nc->full_name); rc = -ENOMEM; goto err_out; }/* Select device driver */
rc = of_modalias_node(nc, spi->modalias, sizeof(spi->modalias)); if (rc < 0) { dev_err(&master->dev, "cannot find modalias for %s\n", nc->full_name); goto err_out; }/* Device address */
rc = of_property_read_u32(nc, "reg", &value); if (rc) { dev_err(&master->dev, "%s has no valid 'reg' property (%d)\n", nc->full_name, rc); goto err_out; } spi->chip_select = value; // 配置片选编号/* Mode (clock phase/polarity/etc.) */
if (of_find_property(nc, "spi-cpha", NULL)) spi->mode |= SPI_CPHA; if (of_find_property(nc, "spi-cpol", NULL)) spi->mode |= SPI_CPOL; if (of_find_property(nc, "spi-cs-high", NULL)) spi->mode |= SPI_CS_HIGH; if (of_find_property(nc, "spi-3wire", NULL)) spi->mode |= SPI_3WIRE; if (of_find_property(nc, "spi-lsb-first", NULL)) spi->mode |= SPI_LSB_FIRST;/* Device DUAL/QUAD mode */
if (!of_property_read_u32(nc, "spi-tx-bus-width", &value)) { switch (value) { case 1: break; case 2: spi->mode |= SPI_TX_DUAL; break; case 4: spi->mode |= SPI_TX_QUAD; break; default: dev_warn(&master->dev, "spi-tx-bus-width %d not supported\n", value); break; } }if (!of_property_read_u32(nc, "spi-rx-bus-width", &value)) {
switch (value) { case 1: break; case 2: spi->mode |= SPI_RX_DUAL; break; case 4: spi->mode |= SPI_RX_QUAD; break; default: dev_warn(&master->dev, "spi-rx-bus-width %d not supported\n", value); break; } }/* Device speed */
rc = of_property_read_u32(nc, "spi-max-frequency", &value); if (rc) { dev_err(&master->dev, "%s has no valid 'spi-max-frequency' property (%d)\n", nc->full_name, rc); goto err_out; } spi->max_speed_hz = value;/* Store a pointer to the node in the device structure */
of_node_get(nc); spi->dev.of_node = nc;/* Register the new device */
rc = spi_add_device(spi); // 注册spi_device到spi_bus_type中 if (rc) { dev_err(&master->dev, "spi_device register error %s\n", nc->full_name); goto err_out; }return spi;
err_out:
spi_dev_put(spi); return ERR_PTR(rc); }int spi_add_device(struct spi_device *spi)
{ static DEFINE_MUTEX(spi_add_lock); struct spi_master *master = spi->master; struct device *dev = master->dev.parent; int status;/* Chipselects are numbered 0..max; validate. */
if (spi->chip_select >= master->num_chipselect) { dev_err(dev, "cs%d >= max %d\n", spi->chip_select, master->num_chipselect); return -EINVAL; }/* Set the bus ID string */
spi_dev_set_name(spi);/* We need to make sure there's no other device with this
* chipselect **BEFORE** we call setup(), else we'll trash * its configuration. Lock against concurrent add() calls. */ mutex_lock(&spi_add_lock);status = bus_for_each_dev(&spi_bus_type, NULL, spi, spi_dev_check);
if (status) { dev_err(dev, "chipselect %d already in use\n", spi->chip_select); goto done; }if (master->cs_gpios) spi->cs_gpio = master->cs_gpios[spi->chip_select]; // 获取片选gpio
/* Drivers may modify this initial i/o setup, but will
* normally rely on the device being setup. Devices * using SPI_CS_HIGH can't coexist well otherwise... */ status = spi_setup(spi); // 内部调用master->setup设置传输参数 if (status < 0) { dev_err(dev, "can't setup %s, status %d\n", dev_name(&spi->dev), status); goto done; }/* Device may be bound to an active driver when this returns */
status = device_add(&spi->dev); // 将spi_device注册进设备驱动框架 if (status < 0) dev_err(dev, "can't add %s, status %d\n", dev_name(&spi->dev), status); else dev_dbg(dev, "registered child %s\n", dev_name(&spi->dev));done:
mutex_unlock(&spi_add_lock); return status; }int spi_setup(struct spi_device *spi)
{ unsigned bad_bits, ugly_bits; int status;/* check mode to prevent that DUAL and QUAD set at the same time
*/ if (((spi->mode & SPI_TX_DUAL) && (spi->mode & SPI_TX_QUAD)) || ((spi->mode & SPI_RX_DUAL) && (spi->mode & SPI_RX_QUAD))) { dev_err(&spi->dev, "setup: can not select dual and quad at the same time\n"); return -EINVAL; } /* if it is SPI_3WIRE mode, DUAL and QUAD should be forbidden */ if ((spi->mode & SPI_3WIRE) && (spi->mode & (SPI_TX_DUAL | SPI_TX_QUAD | SPI_RX_DUAL | SPI_RX_QUAD))) return -EINVAL; /* help drivers fail *cleanly* when they need options * that aren't supported with their current master */ bad_bits = spi->mode & ~spi->master->mode_bits; ugly_bits = bad_bits & (SPI_TX_DUAL | SPI_TX_QUAD | SPI_RX_DUAL | SPI_RX_QUAD); if (ugly_bits) { dev_warn(&spi->dev, "setup: ignoring unsupported mode bits %x\n", ugly_bits); spi->mode &= ~ugly_bits; bad_bits &= ~ugly_bits; } if (bad_bits) { dev_err(&spi->dev, "setup: unsupported mode bits %x\n", bad_bits); return -EINVAL; }if (!spi->bits_per_word)
spi->bits_per_word = 8;status = __spi_validate_bits_per_word(spi->master, spi->bits_per_word);
if (status) return status;if (!spi->max_speed_hz)
spi->max_speed_hz = spi->master->max_speed_hz;if (spi->master->setup)
status = spi->master->setup(spi); // 调用master->setup()spi_set_cs(spi, false); // 先禁止片选
dev_dbg(&spi->dev, "setup mode %d, %s%s%s%s%u bits/w, %u Hz max --> %d\n",
(int) (spi->mode & (SPI_CPOL | SPI_CPHA)), (spi->mode & SPI_CS_HIGH) ? "cs_high, " : "", (spi->mode & SPI_LSB_FIRST) ? "lsb, " : "", (spi->mode & SPI_3WIRE) ? "3wire, " : "", (spi->mode & SPI_LOOP) ? "loopback, " : "", spi->bits_per_word, spi->max_speed_hz, status);return status;
}static void spi_set_cs(struct spi_device *spi, bool enable)
{ if (spi->mode & SPI_CS_HIGH) enable = !enable;if (gpio_is_valid(spi->cs_gpio))
gpio_set_value(spi->cs_gpio, !enable); // 优先设置gpio片选信号 else if (spi->master->set_cs) spi->master->set_cs(spi, !enable); // 否则调用master->set_cs() }(2)数据传输(异步传输):int spi_async(struct spi_device *spi, struct spi_message *message)
int spi_async(struct spi_device *spi, struct spi_message *message)
{ struct spi_master *master = spi->master; int ret; unsigned long flags;ret = __spi_validate(spi, message);
if (ret != 0) return ret;spin_lock_irqsave(&master->bus_lock_spinlock, flags);
if (master->bus_lock_flag)
ret = -EBUSY; else ret = __spi_async(spi, message); // 调用无锁版本spin_unlock_irqrestore(&master->bus_lock_spinlock, flags);
return ret;
}static int __spi_async(struct spi_device *spi, struct spi_message *message)
{ struct spi_master *master = spi->master;message->spi = spi;
SPI_STATISTICS_INCREMENT_FIELD(&master->statistics, spi_async); SPI_STATISTICS_INCREMENT_FIELD(&spi->statistics, spi_async); // 更新统计信息
trace_spi_message_submit(message);
return master->transfer(spi, message); // 调用master->transfer,即spi_queued_transfer(),将spi_message加入消息队列
}static int spi_queued_transfer(struct spi_device *spi, struct spi_message *msg)
{ return __spi_queued_transfer(spi, msg, true); // true表示消息加入队列后,需要启动workqueue线程去处理队列中的消息,因为这个方法只会被异步传输方法调用。 }static int __spi_queued_transfer(struct spi_device *spi,
struct spi_message *msg, bool need_pump) { struct spi_master *master = spi->master; unsigned long flags;spin_lock_irqsave(&master->queue_lock, flags);
if (!master->running) {
spin_unlock_irqrestore(&master->queue_lock, flags); return -ESHUTDOWN; } msg->actual_length = 0; msg->status = -EINPROGRESS;list_add_tail(&msg->queue, &master->queue); // spi_message加入master消息队列
if (!master->busy && need_pump) queue_kthread_work(&master->kworker, &master->pump_messages); // need_pump为true,启动workqueue线程处理消息。其中master->pump_message方法为spi_pump_messages()方法spin_unlock_irqrestore(&master->queue_lock, flags);
return 0; }// spi_pump_messages()运行于workqueue线程
static void spi_pump_messages(struct kthread_work *work)
{ struct spi_master *master = container_of(work, struct spi_master, pump_messages);__spi_pump_messages(master, true); // 执行实际的数据处理
}static void __spi_pump_messages(struct spi_master *master, bool in_kthread)
{ unsigned long flags; bool was_busy = false; int ret;/* Lock queue */
spin_lock_irqsave(&master->queue_lock, flags);/* Make sure we are not already running a message */
if (master->cur_msg) { spin_unlock_irqrestore(&master->queue_lock, flags); return; }/* If another context is idling the device then defer */
if (master->idling) { queue_kthread_work(&master->kworker, &master->pump_messages); spin_unlock_irqrestore(&master->queue_lock, flags); return; }/* Check if the queue is idle */
if (list_empty(&master->queue) || !master->running) { if (!master->busy) { spin_unlock_irqrestore(&master->queue_lock, flags); return; }/* Only do teardown in the thread */
if (!in_kthread) { queue_kthread_work(&master->kworker, &master->pump_messages); spin_unlock_irqrestore(&master->queue_lock, flags); return; }master->busy = false;
master->idling = true; spin_unlock_irqrestore(&master->queue_lock, flags);kfree(master->dummy_rx);
master->dummy_rx = NULL; kfree(master->dummy_tx); master->dummy_tx = NULL; if (master->unprepare_transfer_hardware && master->unprepare_transfer_hardware(master)) // 调用master->unprepare_transfer_hardware结束上一次硬件传输 dev_err(&master->dev, "failed to unprepare transfer hardware\n"); if (master->auto_runtime_pm) { pm_runtime_mark_last_busy(master->dev.parent); pm_runtime_put_autosuspend(master->dev.parent); } trace_spi_master_idle(master);spin_lock_irqsave(&master->queue_lock, flags);
master->idling = false; spin_unlock_irqrestore(&master->queue_lock, flags); return; }/* Extract head of queue */
master->cur_msg = list_first_entry(&master->queue, struct spi_message, queue); // 从消息队列头获取一个messagelist_del_init(&master->cur_msg->queue);
if (master->busy) was_busy = true; else master->busy = true; spin_unlock_irqrestore(&master->queue_lock, flags);if (!was_busy && master->auto_runtime_pm) {
ret = pm_runtime_get_sync(master->dev.parent); if (ret < 0) { dev_err(&master->dev, "Failed to power device: %d\n", ret); return; } }if (!was_busy)
trace_spi_master_busy(master);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");if (master->auto_runtime_pm)
pm_runtime_put(master->dev.parent); return; } }trace_spi_message_start(master->cur_msg);
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; }ret = spi_map_msg(master, master->cur_msg);
if (ret) { master->cur_msg->status = ret; spi_finalize_current_message(master); return; }ret = master->transfer_one_message(master, master->cur_msg); // 传输一个spi_message,即spi_transfer_one_message()
if (ret) { dev_err(&master->dev, "failed to transfer one message from queue\n"); return; } }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; unsigned long ms = 1; struct spi_statistics *statm = &master->statistics; struct spi_statistics *stats = &msg->spi->statistics;spi_set_cs(msg->spi, true);
SPI_STATISTICS_INCREMENT_FIELD(statm, messages);
SPI_STATISTICS_INCREMENT_FIELD(stats, messages);list_for_each_entry(xfer, &msg->transfers, transfer_list) { // 轮询message下的所有transfer
trace_spi_transfer_start(msg, xfer);spi_statistics_add_transfer_stats(statm, xfer, master);
spi_statistics_add_transfer_stats(stats, xfer, master);if (xfer->tx_buf || xfer->rx_buf) {
reinit_completion(&master->xfer_completion);ret = master->transfer_one(master, msg->spi, xfer); // 调用master->transfer_one()传输spi_transfer
if (ret < 0) { SPI_STATISTICS_INCREMENT_FIELD(statm, errors); SPI_STATISTICS_INCREMENT_FIELD(stats, errors); dev_err(&msg->spi->dev, "SPI transfer failed: %d\n", ret); goto out; }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) {
SPI_STATISTICS_INCREMENT_FIELD(statm, timedout); SPI_STATISTICS_INCREMENT_FIELD(stats, timedout); dev_err(&msg->spi->dev, "SPI transfer timed out\n"); msg->status = -ETIMEDOUT; } } else { if (xfer->len) dev_err(&msg->spi->dev, "Bufferless transfer has length %u\n", xfer->len); }trace_spi_transfer_stop(msg, xfer);
if (msg->status != -EINPROGRESS)
goto out;if (xfer->delay_usecs)
udelay(xfer->delay_usecs);if (xfer->cs_change) {
if (list_is_last(&xfer->transfer_list, &msg->transfers)) { keep_cs = true; } else { spi_set_cs(msg->spi, false); udelay(10); spi_set_cs(msg->spi, true); } }msg->actual_length += xfer->len; // 更新实际传输长度
}out:
if (ret != 0 || !keep_cs) spi_set_cs(msg->spi, false);if (msg->status == -EINPROGRESS)
msg->status = ret;if (msg->status && master->handle_err)
master->handle_err(master, msg);spi_finalize_current_message(master); //结束当前消息
return ret;
}注意,master->transter_one由实际spi主设备驱动实现,用来完成实际的传输协议(在后面SPI bitbang中解释)。
(3)数据传输(同步传输):int spi_sync(struct spi_device *spi, struct spi_message *message)
int spi_sync(struct spi_device *spi, struct spi_message *message)
{ return __spi_sync(spi, message, 0); // 同步数据传输 }static int __spi_sync(struct spi_device *spi, struct spi_message *message,
int bus_locked) { DECLARE_COMPLETION_ONSTACK(done); int status; struct spi_master *master = spi->master; unsigned long flags;status = __spi_validate(spi, message);
if (status != 0) return status;message->complete = spi_complete;
message->context = &done; message->spi = spi;SPI_STATISTICS_INCREMENT_FIELD(&master->statistics, spi_sync);
SPI_STATISTICS_INCREMENT_FIELD(&spi->statistics, spi_sync);if (!bus_locked)
mutex_lock(&master->bus_lock_mutex);/* 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 (master->transfer == spi_queued_transfer) { spin_lock_irqsave(&master->bus_lock_spinlock, flags);trace_spi_message_submit(message);
status = __spi_queued_transfer(spi, message, false); // false表示将spi_message放进消息队列,但是不启动workqueue线程处理
spin_unlock_irqrestore(&master->bus_lock_spinlock, flags);
} else { status = spi_async_locked(spi, message); }if (!bus_locked)
mutex_unlock(&master->bus_lock_mutex);if (status == 0) {
/* Push out the messages in the calling context if we * can. */ if (master->transfer == spi_queued_transfer) { SPI_STATISTICS_INCREMENT_FIELD(&master->statistics, spi_sync_immediate); SPI_STATISTICS_INCREMENT_FIELD(&spi->statistics, spi_sync_immediate); __spi_pump_messages(master, false); // 在当前线程中取出消息队列中的消息,同步处理。 }wait_for_completion(&done);
status = message->status; } message->context = NULL; return status; }
SPI master驱动分析:SPI bitbang
spi bitbang是软件模拟的spi主设备驱动。当硬件上没有spi总线主控设备时,可以在软件上模拟spi主控设备,通过gpio信号线同从设备通信。spi bitbang依赖于gpio模拟spi的四根信号线,所以bitbang相关的代码依赖spi-gpio驱动。直接看源码:
static struct platform_driver spi_gpio_driver = {
.driver = { .name = DRIVER_NAME, .of_match_table = of_match_ptr(spi_gpio_dt_ids), }, .probe = spi_gpio_probe, // spi-gpio探测函数 .remove = spi_gpio_remove, };static int spi_gpio_probe(struct platform_device *pdev)
{ int status; struct spi_master *master; struct spi_gpio *spi_gpio; struct spi_gpio_platform_data *pdata; u16 master_flags = 0; bool use_of = 0; int num_devices;status = spi_gpio_probe_dt(pdev); // 从设备树配置中获取spi相关配置信息: MOSI,MISO,SCLK等gpio信息
if (status < 0) return status; if (status > 0) use_of = 1;pdata = dev_get_platdata(&pdev->dev);
#ifdef GENERIC_BITBANG if (!pdata || (!use_of && !pdata->num_chipselect)) return -ENODEV; #endifif (use_of && !SPI_N_CHIPSEL)
num_devices = 1; else num_devices = SPI_N_CHIPSEL;status = spi_gpio_request(pdata, dev_name(&pdev->dev), &master_flags); // 请求MOSI,MISO,SCLK等gpio信息
if (status < 0) return status;master = spi_alloc_master(&pdev->dev, sizeof(*spi_gpio) + (sizeof(unsigned long) * num_devices)); // 分配spi_master结构对象
if (!master) { status = -ENOMEM; goto gpio_free; } spi_gpio = spi_master_get_devdata(master); platform_set_drvdata(pdev, spi_gpio);spi_gpio->pdev = pdev;
if (pdata) spi_gpio->pdata = *pdata;master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32);
master->flags = master_flags; master->bus_num = pdev->id; master->num_chipselect = num_devices; master->setup = spi_gpio_setup; master->cleanup = spi_gpio_cleanup; // 设置setup和cleanup方法 #ifdef CONFIG_OF master->dev.of_node = pdev->dev.of_node;if (use_of) {
int i; struct device_node *np = pdev->dev.of_node;/*
* In DT environments, take the CS GPIO from the "cs-gpios" * property of the node. */if (!SPI_N_CHIPSEL)
spi_gpio->cs_gpios[0] = SPI_GPIO_NO_CHIPSELECT; else for (i = 0; i < SPI_N_CHIPSEL; i++) { status = of_get_named_gpio(np, "cs-gpios", i); if (status < 0) { dev_err(&pdev->dev, "invalid cs-gpios property\n"); goto gpio_free; } spi_gpio->cs_gpios[i] = status; } } #endifspi_gpio->bitbang.master = master;
spi_gpio->bitbang.chipselect = spi_gpio_chipselect; // 设置spi bitbang的片选方法// 初始化4种时钟模式下的传输方法
if ((master_flags & (SPI_MASTER_NO_TX | SPI_MASTER_NO_RX)) == 0) { spi_gpio->bitbang.txrx_word[SPI_MODE_0] = spi_gpio_txrx_word_mode0; spi_gpio->bitbang.txrx_word[SPI_MODE_1] = spi_gpio_txrx_word_mode1; spi_gpio->bitbang.txrx_word[SPI_MODE_2] = spi_gpio_txrx_word_mode2; spi_gpio->bitbang.txrx_word[SPI_MODE_3] = spi_gpio_txrx_word_mode3;
} else { spi_gpio->bitbang.txrx_word[SPI_MODE_0] = spi_gpio_spec_txrx_word_mode0; spi_gpio->bitbang.txrx_word[SPI_MODE_1] = spi_gpio_spec_txrx_word_mode1; spi_gpio->bitbang.txrx_word[SPI_MODE_2] = spi_gpio_spec_txrx_word_mode2; spi_gpio->bitbang.txrx_word[SPI_MODE_3] = spi_gpio_spec_txrx_word_mode3; } spi_gpio->bitbang.setup_transfer = spi_bitbang_setup_transfer; //设置bitbang的setup_transfer函数 spi_gpio->bitbang.flags = SPI_CS_HIGH; // 片选信号,高电平有效status = spi_bitbang_start(&spi_gpio->bitbang); // 启动bitbang,并注册master
if (status < 0) { gpio_free: if (SPI_MISO_GPIO != SPI_GPIO_NO_MISO) gpio_free(SPI_MISO_GPIO); if (SPI_MOSI_GPIO != SPI_GPIO_NO_MOSI) gpio_free(SPI_MOSI_GPIO); gpio_free(SPI_SCK_GPIO); spi_master_put(master); }return status;
}int spi_bitbang_start(struct spi_bitbang *bitbang)
{ struct spi_master *master = bitbang->master; int ret;if (!master || !bitbang->chipselect)
return -EINVAL;mutex_init(&bitbang->lock);
if (!master->mode_bits)
master->mode_bits = SPI_CPOL | SPI_CPHA | bitbang->flags;if (master->transfer || master->transfer_one_message)
return -EINVAL;master->prepare_transfer_hardware = spi_bitbang_prepare_hardware; master->unprepare_transfer_hardware = spi_bitbang_unprepare_hardware; master->transfer_one = spi_bitbang_transfer_one; master->set_cs = spi_bitbang_set_cs; // 设置bitbang硬件准备相关的函数,设置片选函数和spi_transfer传输函数
if (!bitbang->txrx_bufs) {
bitbang->use_dma = 0; bitbang->txrx_bufs = spi_bitbang_bufs; if (!master->setup) { if (!bitbang->setup_transfer) bitbang->setup_transfer = spi_bitbang_setup_transfer; master->setup = spi_bitbang_setup; // 注册时调用bitbang_setup函数 master->cleanup = spi_bitbang_cleanup; } }/* driver may get busy before register() returns, especially
* if someone registered boardinfo for devices */ ret = spi_register_master(spi_master_get(master)); // 注册bitbang master if (ret) spi_master_put(master);return 0;
} (1)注册master加载每个spi_devices时,调用master->setup,即spi_bitbang_setup:int spi_bitbang_setup(struct spi_device *spi)
{ struct spi_bitbang_cs *cs = spi->controller_state; struct spi_bitbang *bitbang;bitbang = spi_master_get_devdata(spi->master);
if (!cs) {
cs = kzalloc(sizeof(*cs), GFP_KERNEL); if (!cs) return -ENOMEM; spi->controller_state = cs; }/* per-word shift register access, in hardware or bitbanging */
cs->txrx_word = bitbang->txrx_word[spi->mode & (SPI_CPOL|SPI_CPHA)]; // 根据每个spi_device设备支持的模式选择不同的传输函数 if (!cs->txrx_word) return -EINVAL;if (bitbang->setup_transfer) { int retval = bitbang->setup_transfer(spi, NULL); // NULL表示,调用spi_bitbang_setup_transfer()设置spi_device的默认传输函数和速率
if (retval < 0) return retval; }dev_dbg(&spi->dev, "%s, %u nsec/bit\n", __func__, 2 * cs->nsecs);
/* NOTE we _need_ to call chipselect() early, ideally with adapter
* setup, unless the hardware defaults cooperate to avoid confusion * between normal (active low) and inverted chipselects. *//* deselect chip (low or high) */
mutex_lock(&bitbang->lock); if (!bitbang->busy) { bitbang->chipselect(spi, BITBANG_CS_INACTIVE); // 调用spi_gpio_chipselect() ndelay(cs->nsecs); } mutex_unlock(&bitbang->lock);return 0;
}int spi_bitbang_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
{ struct spi_bitbang_cs *cs = spi->controller_state; u8 bits_per_word; u32 hz;if (t) {
bits_per_word = t->bits_per_word; hz = t->speed_hz; } else { bits_per_word = 0; hz = 0; }/* spi_transfer level calls that work per-word */
if (!bits_per_word) bits_per_word = spi->bits_per_word;// 设置spi_device各位宽传输函数
if (bits_per_word <= 8) cs->txrx_bufs = bitbang_txrx_8; else if (bits_per_word <= 16) cs->txrx_bufs = bitbang_txrx_16; else if (bits_per_word <= 32) cs->txrx_bufs = bitbang_txrx_32; else return -EINVAL;/* nsecs = (clock period)/2 */
// 设置spi_device的传输速率
if (!hz) hz = spi->max_speed_hz; if (hz) { cs->nsecs = (1000000000/2) / hz; if (cs->nsecs > (MAX_UDELAY_MS * 1000 * 1000)) return -EINVAL; }return 0;
}static void spi_gpio_chipselect(struct spi_device *spi, int is_active)
{ struct spi_gpio *spi_gpio = spi_to_spi_gpio(spi); unsigned long cs = spi_gpio->cs_gpios[spi->chip_select];/* set initial clock polarity */
if (is_active) setsck(spi, spi->mode & SPI_CPOL);if (cs != SPI_GPIO_NO_CHIPSELECT) {
/* SPI is normally active-low */ gpio_set_value_cansleep(cs, (spi->mode & SPI_CS_HIGH) ? is_active : !is_active); // 设置片选信号 } }(2)数据传输过程到master->transfer_one,即调用spi_bitbang_transfer_one:
static int spi_bitbang_transfer_one(struct spi_master *master,
struct spi_device *spi, struct spi_transfer *transfer) { struct spi_bitbang *bitbang = spi_master_get_devdata(master); int status = 0;if (bitbang->setup_transfer) {
status = bitbang->setup_transfer(spi, transfer); // 先设置spi的传输函数和传输速率 if (status < 0) goto out; }if (transfer->len)
status = bitbang->txrx_bufs(spi, transfer); // 调用实际的传输函数,即spi_bitbang_bufsif (status == transfer->len)
status = 0; else if (status >= 0) status = -EREMOTEIO;out:
spi_finalize_current_transfer(master);return status;
}static int spi_bitbang_bufs(struct spi_device *spi, struct spi_transfer *t)
{ struct spi_bitbang_cs *cs = spi->controller_state; unsigned nsecs = cs->nsecs;return cs->txrx_bufs(spi, cs->txrx_word, nsecs, t); // 根据spi_device的片选传输字长选取不同的传输函数
}以8bit传输函数为例:
static unsigned bitbang_txrx_8(
struct spi_device *spi, u32 (*txrx_word)(struct spi_device *spi, unsigned nsecs, u32 word, u8 bits), unsigned ns, struct spi_transfer *t ) { unsigned bits = t->bits_per_word; unsigned count = t->len; const u8 *tx = t->tx_buf; u8 *rx = t->rx_buf;while (likely(count > 0)) {
u8 word = 0;if (tx)
word = *tx++; word = txrx_word(spi, ns, word, bits); // 调用实际传输函数spi_gpio_txrx_word_modex if (rx) *rx++ = word; count -= 1; } return t->len - count; }以spi_gpio_txrx_word_mode0为例,
static u32 spi_gpio_txrx_word_mode0(struct spi_device *spi,
unsigned nsecs, u32 word, u8 bits) { return bitbang_txrx_be_cpha0(spi, nsecs, 0, 0, word, bits); // 调用bitbang模拟收发函数 }// 软件模拟SCLK,MISO和MOSI信号实现数据收发
static inline u32
bitbang_txrx_be_cpha0(struct spi_device *spi, unsigned nsecs, unsigned cpol, unsigned flags, u32 word, u8 bits) { /* if (cpol == 0) this is SPI_MODE_0; else this is SPI_MODE_2 */u32 oldbit = (!(word & (1<<(bits-1)))) << 31;
/* clock starts at inactive polarity */ for (word <<= (32 - bits); likely(bits); bits--) {/* setup MSB (to slave) on trailing edge */
if ((flags & SPI_MASTER_NO_TX) == 0) { if ((word & (1 << 31)) != oldbit) { setmosi(spi, word & (1 << 31)); oldbit = word & (1 << 31); } } spidelay(nsecs); /* T(setup) */setsck(spi, !cpol);
spidelay(nsecs);/* sample MSB (from slave) on leading edge */
word <<= 1; if ((flags & SPI_MASTER_NO_RX) == 0) word |= getmiso(spi); setsck(spi, cpol); } return word; }