详细追踪从spi.c中的函数接口 spi_write() 到 spi-imx.c 中具体硬件操作的完整调用链。
完整的函数调用链
c
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
第1步:应用层/设备驱动调用
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// oled_drv.c - 具体的字符设备驱动程序
static void spi_write_datas(const unsigned char *buf, int len)
{
spi_write(oled, buf, len);
// ↑
// oled 是 struct spi_device*
}
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
第2步:SPI 核心层 - spi_write() - spi.c 作为核心层
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// drivers/spi/spi.c
int spi_write(struct spi_device *spi, const void *buf, size_t len)
{
struct spi_transfer t = {
.tx_buf = buf,
.len = len,
};
return spi_sync_transfer(spi, &t, 1);
// ↓
}
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
第3步:SPI 核心层 - spi_sync_transfer()
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// drivers/spi/spi.c
int spi_sync_transfer(struct spi_device *spi,
struct spi_transfer *xfers,
unsigned int num_xfers)
{
struct spi_message msg;
// 初始化消息
spi_message_init(&msg);
// 将 transfer 加入消息
spi_message_add_tail(&xfers[0], &msg);
// ↓
// msg.transfers 链表中有一个 transfer
return spi_sync(spi, &msg);
// ↓
}
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
第4步:SPI 核心层 - spi_sync()
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// drivers/spi/spi.c
int spi_sync(struct spi_device *spi, struct spi_message *message)
{
int ret;
mutex_lock(&spi->master->bus_lock_mutex);
ret = __spi_sync(spi, message);
// ↓
mutex_unlock(&spi->master->bus_lock_mutex);
return ret;
}
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
第5步:SPI 核心层 - __spi_sync()
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// drivers/spi/spi.c
static int __spi_sync(struct spi_device *spi, struct spi_message *message)
{
DECLARE_COMPLETION_ONSTACK(done);
int status;
struct spi_master *master = spi->master;
// ↑
// 获取对应的 spi_master
// 这个 master 是 spi-imx.c 创建的
// 验证消息
status = __spi_validate(spi, message);
if (status != 0)
return status;
// 设置完成回调
message->complete = spi_complete;
message->context = &done;
message->spi = spi;
// 关键判断:新方法还是老方法
if (master->transfer == spi_queued_transfer) {
// ↑
// master->transfer 在 spi_register_master() 时设置的
// 如果 spi-imx.c 没有实现 master->transfer
// 内核会自动设置为 spi_queued_transfer
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 新方法(队列化传输)- 大多数驱动走这里
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
spin_lock_irqsave(&master->bus_lock_spinlock, flags);
status = __spi_queued_transfer(spi, message, false);
// ↓
spin_unlock_irqrestore(&master->bus_lock_spinlock, flags);
if (status == 0) {
// 在当前上下文中处理(优化)
__spi_pump_messages(master, false);
// ↓
// 等待完成
wait_for_completion(&done);
status = message->status;
}
} else {
// 老方法(直接调用驱动的 transfer 函数)
status = spi_async_locked(spi, message);
}
return status;
}
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
第6步:SPI 核心层 - __spi_queued_transfer()
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// drivers/spi/spi.c
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);
// 检查 master 是否运行
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);
// ↑
// 消息现在在队列中等待处理
// 如果需要,唤醒工作线程
if (!master->busy && need_pump)
kthread_queue_work(&master->kworker, &master->pump_messages);
spin_unlock_irqrestore(&master->queue_lock, flags);
return 0;
}
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
第7步:SPI 核心层 - __spi_pump_messages()
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// drivers/spi/spi.c
static void __spi_pump_messages(struct spi_master *master, bool in_kthread)
{
unsigned long flags;
bool was_busy = false;
int ret;
// 获取队列中的第一条消息
spin_lock_irqsave(&master->queue_lock, flags);
if (list_empty(&master->queue) || !master->running) {
master->busy = false;
spin_unlock_irqrestore(&master->queue_lock, flags);
return;
}
// 取出消息
master->cur_msg = list_first_entry(&master->queue,
struct spi_message, queue);
list_del_init(&master->cur_msg->queue);
master->busy = true;
spin_unlock_irqrestore(&master->queue_lock, flags);
// 准备硬件(如果定义了)
if (!was_busy && master->prepare_transfer_hardware) {
ret = master->prepare_transfer_hardware(master);
// ↓
// 这可能调用到 spi-imx.c 的函数
}
// 准备消息(如果定义了)
if (master->prepare_message) {
ret = master->prepare_message(master, master->cur_msg);
// ↓
// 这可能调用到 spi-imx.c 的函数
}
// 关键:传输消息
if (master->transfer_one_message) {
// 方式A:一次传输整个 message
ret = master->transfer_one_message(master, master->cur_msg);
// ↓
// 这会调用到 spi-imx.c 的函数!
} else {
// 方式B:逐个传输 transfer(大多数驱动用这个)
ret = spi_transfer_one_message(master, master->cur_msg);
// ↓
}
}
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
第8步:SPI 核心层 - spi_transfer_one_message()
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// drivers/spi/spi.c
static int spi_transfer_one_message(struct spi_master *master,
struct spi_message *msg)
{
struct spi_transfer *xfer;
int ret = 0;
// 设置片选
spi_set_cs(msg->spi, true);
// 遍历消息中的所有 transfer
list_for_each_entry(xfer, &msg->transfers, transfer_list) {
// ↑
// msg->transfers 链表中的每个 transfer
// 传输单个 transfer
ret = master->transfer_one(master, msg->spi, xfer);
// ↑
// 关键!这里调用 spi-imx.c 的 transfer_one 函数
// ↓
// ↓
// 到达 spi-imx.c!
if (ret < 0) {
// 传输失败
spi_transfer_one_message_failed(master, msg, ret);
return ret;
}
// 如果需要延迟
if (xfer->delay_usecs)
udelay(xfer->delay_usecs);
// 如果需要改变片选
if (xfer->cs_change) {
spi_set_cs(msg->spi, false);
udelay(10);
spi_set_cs(msg->spi, true);
}
}
// 释放片选
spi_set_cs(msg->spi, false);
// 完成消息
msg->status = 0;
spi_finalize_current_message(master);
return 0;
}
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
第9步:SPI Master 驱动 - spi_imx_transfer_one()
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// drivers/spi/spi-imx.c
static int spi_imx_transfer_one(struct spi_master *master,
struct spi_device *spi,
struct spi_transfer *transfer)
{
struct spi_imx_data *spi_imx = spi_master_get_devdata(master);
unsigned long hz_per_byte, byte_limit;
// 配置传输参数
spi_imx->speed_hz = transfer->speed_hz;
spi_imx->bits_per_word = transfer->bits_per_word;
spi_imx->count = transfer->len;
spi_imx->tx_buf = transfer->tx_buf;
spi_imx->rx_buf = transfer->rx_buf;
spi_imx->txfifo = 0;
// 重新初始化完成量
reinit_completion(&spi_imx->xfer_done);
// 配置 SPI 控制器寄存器
spi_imx_config(spi_imx);
// ↓
// 写硬件寄存器
// 根据传输大小和是否支持 DMA 选择传输方式
if (spi_imx->usedma) {
// 使用 DMA 传输
ret = spi_imx_dma_transfer(spi_imx, transfer);
// ↓
wait_for_completion(&spi_imx->dma_tx_completion);
wait_for_completion(&spi_imx->dma_rx_completion);
} else {
// 使用 PIO(中断)传输
// 启动传输(写 FIFO,触发中断)
spi_imx_push(spi_imx);
// ↓
// 写数据到 TX FIFO
// 启用中断
// 等待传输完成
wait_for_completion(&spi_imx->xfer_done);
// ↑
// 中断处理函数会调用 complete(&spi_imx->xfer_done)
}
return 0;
}
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
第10步:硬件操作 - spi_imx_config()
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// drivers/spi/spi-imx.c
static int spi_imx_config(struct spi_imx_data *spi_imx)
{
unsigned int ctrl = MX51_ECSPI_CTRL_ENABLE;
u32 clkdiv;
// 计算时钟分频
clkdiv = spi_imx_clkdiv_2(spi_imx->spi_clk, spi_imx->speed_hz);
// 配置控制寄存器
ctrl |= (spi_imx->bits_per_word - 1) << MX51_ECSPI_CTRL_BL_OFFSET;
if (spi_imx->spi->mode & SPI_CPHA)
ctrl |= MX51_ECSPI_CTRL_PHA;
if (spi_imx->spi->mode & SPI_CPOL)
ctrl |= MX51_ECSPI_CTRL_POL;
// 写寄存器
writel(ctrl, spi_imx->base + MX51_ECSPI_CTRL);
// ↑
// 直接写硬件寄存器!
writel(clkdiv, spi_imx->base + MX51_ECSPI_CONFIG);
return 0;
}
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
第11步:硬件操作 - spi_imx_push()
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// drivers/spi/spi-imx.c
static void spi_imx_push(struct spi_imx_data *spi_imx)
{
unsigned int burst_length;
// 计算可以发送多少字节
burst_length = spi_imx_get_fifosize(spi_imx) - spi_imx->txfifo;
// 填充 TX FIFO
while (spi_imx->txfifo < burst_length && spi_imx->count) {
if (spi_imx->tx_buf) {
// 发送数据
spi_imx->tx(spi_imx);
// ↓
// 根据字长调用不同的函数
// 写数据到 TX FIFO 寄存器
} else {
// 发送 dummy 数据
writel(0, spi_imx->base + MXC_CSPITXDATA);
}
spi_imx->txfifo++;
}
// 启用中断
if (!spi_imx->usedma)
spi_imx_intctrl(spi_imx, MXC_INT_TE | MXC_INT_RR);
// ↑
// 启用发送空和接收就绪中断
}
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
第12步:中断处理 - spi_imx_isr()
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// drivers/spi/spi-imx.c
static irqreturn_t spi_imx_isr(int irq, void *dev_id)
{
struct spi_imx_data *spi_imx = dev_id;
// 读取接收到的数据
while (spi_imx->txfifo > 0) {
// 从 RX FIFO 读取
spi_imx->rx(spi_imx);
// ↓
// readl(spi_imx->base + MXC_CSPIRXDATA)
spi_imx->txfifo--;
}
// 如果还有数据要发送
if (spi_imx->count) {
spi_imx_push(spi_imx); // 继续发送
return IRQ_HANDLED;
}
// 传输完成
if (spi_imx->txfifo == 0) {
// 禁用中断
spi_imx_intctrl(spi_imx, 0);
// 通知传输完成
complete(&spi_imx->xfer_done);
// ↑
// 这会唤醒 spi_imx_transfer_one() 中的 wait_for_completion()
}
return IRQ_HANDLED;
}
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
返回路径:层层返回
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
spi_imx_transfer_one() 返回
↓
spi_transfer_one_message() 继续下一个 transfer 或完成
↓
spi_finalize_current_message() 调用完成回调
↓
spi_complete() 被调用
↓
complete(&done) // __spi_sync() 中的完成量
↓
wait_for_completion(&done) 返回 // __spi_sync() 中
↓
__spi_sync() 返回
↓
spi_sync() 返回
↓
spi_sync_transfer() 返回
↓
spi_write() 返回
↓
spi_write_datas() 返回 // 你的代码
关键连接点
连接点1:spi_device → spi_master
c
// oled_drv.c
static struct spi_device *oled;
static int spidev_probe(struct spi_device *spi)
{
oled = spi;
// spi->master 指向 spi-imx.c 创建的 spi_master
}
// 调用时
spi_write(oled, buf, len);
// ↓
// struct spi_master *master = oled->master;
// ↓
// 这个 master 就是 spi-imx.c 中的 master
连接点2:函数指针跳转
c
// spi-imx.c 注册时设置的
static int spi_imx_probe(struct platform_device *pdev)
{
struct spi_master *master;
master = spi_alloc_master(...);
// 设置函数指针
master->transfer_one = spi_imx_transfer_one;
// ↑
// 这个函数的地址保存在 master 结构中
spi_register_master(master);
}
// SPI 核心层调用时
// drivers/spi/spi.c
ret = master->transfer_one(master, msg->spi, xfer);
// ↑
// 通过函数指针调用
// 实际调用的是 spi_imx_transfer_one()
完整调用链图示
oled_drv.c:spi_write_datas()
↓ 调用
spi.c:spi_write()
↓ 调用
spi.c:spi_sync_transfer()
↓ 调用
spi.c:spi_sync()
↓ 调用
spi.c:__spi_sync()
↓ 调用
spi.c:__spi_queued_transfer() [消息入队]
↓ 返回
spi.c:__spi_pump_messages() [从队列取消息]
↓ 调用
spi.c:spi_transfer_one_message() [遍历 transfers]
↓ 调用 (函数指针)
spi-imx.c:spi_imx_transfer_one() ← 进入硬件驱动!
↓ 调用
spi-imx.c:spi_imx_config() [配置硬件寄存器]
↓ 调用
spi-imx.c:spi_imx_push() [写 TX FIFO]
↓ 启用中断
↓ wait_for_completion() [等待中断]
↑ complete()
spi-imx.c:spi_imx_isr() [中断处理]
↓ 返回
spi-imx.c:spi_imx_transfer_one() 返回
↓ 返回
spi.c:spi_transfer_one_message() 返回
↓ 调用
spi.c:spi_finalize_current_message()
↓ 调用回调
spi.c:spi_complete()
↓ complete(&done)
spi.c:__spi_sync() 的 wait_for_completion() 返回
↓ 层层返回
oled_drv.c:spi_write_datas() 返回
数据结构关系
c
// 数据结构的关联关系
struct spi_device *oled {
.master = &imx_spi_master, // 指向 spi-imx.c 创建的 master
// ...
}
↓ 关联
struct spi_master imx_spi_master {
.transfer_one = spi_imx_transfer_one, // 函数指针
.prepare_transfer_hardware = spi_imx_prepare_hardware,
.unprepare_transfer_hardware = spi_imx_unprepare_hardware,
// ...
}
↓ 实现
// spi-imx.c 中的实际函数
static int spi_imx_transfer_one(...) { ... }
static int spi_imx_prepare_hardware(...) { ... }
static int spi_imx_unprepare_hardware(...) { ... }
总结
| 步骤 | 函数 | 文件 | 说明 |
|---|---|---|---|
| 1 | spi_write_datas() |
oled_drv.c | 你的驱动调用 |
| 2 | spi_write() |
spi.c | SPI 核心 API |
| 3 | spi_sync_transfer() |
spi.c | 构造消息 |
| 4 | spi_sync() |
spi.c | 同步传输 |
| 5 | __spi_sync() |
spi.c | 核心同步逻辑 |
| 6 | __spi_queued_transfer() |
spi.c | 消息入队 |
| 7 | __spi_pump_messages() |
spi.c | 处理消息队列 |
| 8 | spi_transfer_one_message() |
spi.c | 遍历 transfers |
| 9 | master->transfer_one() |
函数指针 | 跳转到硬件驱动 |
| 10 | spi_imx_transfer_one() |
spi-imx.c | i.MX 硬件传输 |
| 11 | spi_imx_config() |
spi-imx.c | 配置硬件 |
| 12 | spi_imx_push() |
spi-imx.c | 写 FIFO |
| 13 | spi_imx_isr() |
spi-imx.c | 中断处理 |
关键点 :从 SPI 核心层到具体硬件驱动的跳转是通过 master->transfer_one 函数指针实现的!