2026/6/1 9:31:40
网站建设
项目流程
无锡网站建设书生商友,网页模板免费下载源代码,wordpress一定是主页吗,十大广告公司spi-imx.c 分析策略与核心流程
一、spi-imx.c分析顺序
1. probe函数 → 理解初始化做了什么
2. 回调函数注册 → 找到关键回调
3. 数据传输路径 → 跟踪实际传输流程
4. 硬件操作细节 → 理解寄存器操作二、核心关键#xff1a;spi-bitbang.c 的介入
重大发现
/* spi_imx_…spi-imx.c 分析策略与核心流程一、spi-imx.c分析顺序1. probe函数 → 理解初始化做了什么 2. 回调函数注册 → 找到关键回调 3. 数据传输路径 → 跟踪实际传输流程 4. 硬件操作细节 → 理解寄存器操作二、核心关键spi-bitbang.c 的介入重大发现/* spi_imx_probe 中 */spi_imx-bitbang.chipselectspi_imx_chipselect;spi_imx-bitbang.setup_transferspi_imx_setupxfer;spi_imx-bitbang.txrx_bufsspi_imx_transfer;// ← 最关键retspi_bitbang_start(spi_imx-bitbang);// ← 这里注册了回调关键理解spi-imx.c只实现了简单的transfer_one单次传输接口在bitbang.c中初始化为master-transfer_one spi_bitbang_transfer_one而没有实现复杂的transfer_one_message整个消息处理接口因此内核会自动使用核心层中的函数spi_transfer_one_message来作为“总指挥”。核心层的spi_transfer_one_message中在发起每一次的xfer单次传输时都会调用master-transfer_one也就是spi_bitbang_transfer_one而在函数spi_bitbang_transfer_one中会调用txrx_bufs(spi, transfer)也就是spi_imx_transfer。spi_transfer_one_message-transfer_one-spi_bitbang_transfer_one-txrx_bufs-spi_imx_transfer.三、调用链重建从spi.c到spi-imx.c的完整路径用户态 ioctl(SPI_IOC_MESSAGE, xfer) ↓ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ VFS层 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ sys_ioctl() ↓ file-f_op-unlocked_ioctl ↓ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ drivers/spi/spidev.c ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ spidev_ioctl() ↓ 识别命令SPI_IOC_MESSAGE ↓ spidev_message() ├─ 拷贝TX数据copy_from_user(tx_buf, user_tx, len) ├─ 构造spi_transfer和spi_message └─ 调用 spi_sync() ↓ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ drivers/spi/spi.cSPI核心层 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ spi_sync() ↓ __spi_sync() ├─ 设置完成量 └─ 调用 __spi_async() ↓ __spi_async() ├─ 验证参数 └─ 将message加入队列 ↓ __spi_pump_messages() ← 队列处理函数 ├─ 从队列取出message ├─ 准备硬件prepare_transfer_hardware ├─ 准备消息prepare_message ├─ 映射DMAspi_map_msg └─ 调用 master-transfer_one_message() ← 关键跳转 ↓ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ drivers/spi/spi.cSPI核心层的默认实现 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ spi_transfer_one_message() ← 核心层提供的包装函数 ↓ /* 关键在这里遍历message */ list_for_each_entry(xfer, msg-transfers, transfer_list) { ↓ /* 调用驱动的transfer_one */ ret master-transfer_one(master, msg-spi, xfer); ↓ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ drivers/spi/spi-bitbang.cBitbang框架 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ spi_bitbang_transfer_one() ← 只处理单个transfer ↓ /* 配置传输参数 */ if (bitbang-setup_transfer) bitbang-setup_transfer(spi, t); → spi_imx_setupxfer() ↓ /* 执行实际传输 */ status bitbang-txrx_bufs(spi, t); → spi_imx_transfer() ↓ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ drivers/spi/spi-imx.c平台驱动 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ spi_imx_transfer() ← 处理单个transfer ↓ if (spi_imx-usedma) spi_imx_dma_transfer() else spi_imx_pio_transfer() ↓ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ PIO模式详细流程 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ spi_imx_pio_transfer() ├─ 设置缓冲区指针tx_buf, rx_buf, count ├─ 重置完成量reinit_completion(xfer_done) ├─ 填充TX FIFOspi_imx_push() │ ↓ │ while (txfifo FIFO_SIZE count 0) { │ spi_imx-tx(spi_imx) → 写寄存器 │ txfifo │ } │ ↓ │ devtype_data-trigger() → 启动硬件传输 │ ├─ 使能中断intctrl(spi_imx, MXC_INT_TE) └─ 等待完成wait_for_completion(xfer_done) ↓ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 中断处理 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ spi_imx_isr() ← 硬件中断触发 ↓ /* 读取RX FIFO */ while (rx_available()) { spi_imx-rx(spi_imx) → 读寄存器 txfifo-- } ↓ if (count 0) { /* 还有数据继续发送 */ spi_imx_push() } else if (txfifo 0) { /* 等待最后的接收 */ intctrl(spi_imx, MXC_INT_RR) } else { /* 传输完成 */ intctrl(spi_imx, 0) → 关闭中断 complete(xfer_done) → 唤醒等待线程 } ↓ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 返回路径 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ complete(xfer_done)唤醒 ↓ spi_imx_pio_transfer() 返回 ↓ spi_imx_transfer() 返回 ↓ spi_bitbang_transfer_one() 返回 ↓ (继续处理下一个transfer) } ← 结束for_each_entry循环 ↓ spi_transfer_one_message() 完成 ↓ spi_finalize_current_message() ├─ unprepare_message() → 关闭时钟 ├─ master-cur_msg NULL └─ complete(msg-context) → 唤醒用户线程 ↓ __spi_sync() 被唤醒 ↓ spi_sync() 返回 ↓ spidev_message() 返回 ├─ 拷贝RX数据copy_to_user(user_rx, rx_buf, len) └─ 返回传输字节数 ↓ spidev_ioctl() 返回 ↓ 用户态ioctl() 返回四、关键函数详解4.1 spi_bitbang_start注册回调// drivers/spi/spi-bitbang.cintspi_bitbang_start(structspi_bitbang*bitbang){structspi_master*masterbitbang-master;/* 关键注册 transfer_one_message 回调 */if(!master-transfer_one_message)master-transfer_one_messagespi_bitbang_transfer_one;/* 其他初始化... */returnspi_register_master(master);}4.2 spi_bitbang_transfer_onebitbang核心// drivers/spi/spi-bitbang.cstaticintspi_bitbang_transfer_one(structspi_master*master,structspi_message*msg){structspi_bitbang*bitbangspi_master_get_devdata(master);structspi_transfer*t;printk([BITBANG_TRACE] transfer_one: msg%px\n,msg);/* 遍历消息中的每个传输段 */list_for_each_entry(t,msg-transfers,transfer_list){printk([BITBANG_TRACE] Processing transfer: len%u\n,t-len);/* 1. 片选激活 */if(bitbang-chipselect){bitbang-chipselect(msg-spi,BITBANG_CS_ACTIVE);}/* 2. 配置传输参数速度、位宽等 */if(bitbang-setup_transfer){bitbang-setup_transfer(msg-spi,t);}/* 3. 执行实际传输 ← 最关键 */if(bitbang-txrx_bufs){statusbitbang-txrx_bufs(msg-spi,t);// ↑ 调用 spi_imx_transfer()}/* 4. 延迟如果需要 */if(t-delay_usecs)udelay(t-delay_usecs);/* 5. 片选控制 */if(t-cs_change){bitbang-chipselect(msg-spi,BITBANG_CS_INACTIVE);}}/* 6. 传输完成调用回调 */msg-status0;msg-actual_length/* 累加所有transfer的len */;spi_finalize_current_message(master);return0;}五、spi-imx.c 分析要点5.1 probe函数初始化staticintspi_imx_probe(structplatform_device*pdev){structspi_master*master;structspi_imx_data*spi_imx;/* 1. 分配master */masterspi_alloc_master(pdev-dev,sizeof(*spi_imx));spi_imxspi_master_get_devdata(master);spi_imx-bitbang.mastermaster;/* 2. 识别芯片型号从设备树 */spi_imx-devtype_dataof_id-data;// ↑ 指向 imx51_ecspi_devtype_data/* 3. 注册bitbang回调 ← 你找到的关键代码 */spi_imx-bitbang.chipselectspi_imx_chipselect;spi_imx-bitbang.setup_transferspi_imx_setupxfer;spi_imx-bitbang.txrx_bufsspi_imx_transfer;// ← 传输入口/* 4. 注册master回调 */spi_imx-bitbang.master-setupspi_imx_setup;spi_imx-bitbang.master-prepare_messagespi_imx_prepare_message;spi_imx-bitbang.master-unprepare_messagespi_imx_unprepare_message;/* 5. 初始化硬件资源 */spi_imx-basedevm_ioremap_resource(pdev-dev,res);// 寄存器映射spi_imx-clk_perdevm_clk_get(pdev-dev,per);// 时钟/* 6. 注册中断 */devm_request_irq(pdev-dev,irq,spi_imx_isr,0,...);/* 7. 初始化DMA如果支持 */if(is_imx51_ecspi(spi_imx)){spi_imx_sdma_init(pdev-dev,spi_imx,master);}/* 8. 复位硬件 */spi_imx-devtype_data-reset(spi_imx);// ↑ 调用 mx51_ecspi_reset()/* 9. 启动bitbang框架 ← 这里注册transfer_one_message */retspi_bitbang_start(spi_imx-bitbang);return0;}5.2 devtype_data芯片差异抽象staticstructspi_imx_devtype_dataimx51_ecspi_devtype_data{.intctrlmx51_ecspi_intctrl,// 中断控制.configmx51_ecspi_config,// 硬件配置.triggermx51_ecspi_trigger,// 启动传输.rx_availablemx51_ecspi_rx_available,// 检查RX FIFO.resetmx51_ecspi_reset,// 复位控制器.devtypeIMX51_ECSPI,};设计模式函数指针表实现多型号支持六、核心传输流程6.1 spi_imx_transfer传输入口staticintspi_imx_transfer(structspi_device*spi,structspi_transfer*transfer){structspi_imx_data*spi_imxspi_master_get_devdata(spi-master);printk([SPI_IMX_TRACE] transfer: len%u, usedma%d\n,transfer-len,spi_imx-usedma);if(spi_imx-usedma)returnspi_imx_dma_transfer(spi_imx,transfer);elsereturnspi_imx_pio_transfer(spi,transfer);}6.2 PIO模式传输中断方式staticintspi_imx_pio_transfer(structspi_device*spi,structspi_transfer*transfer){structspi_imx_data*spi_imxspi_master_get_devdata(spi-master);printk([SPI_IMX_TRACE] pio_transfer: ENTER\n);/* 1. 设置缓冲区指针 */spi_imx-tx_buftransfer-tx_buf;spi_imx-rx_buftransfer-rx_buf;spi_imx-counttransfer-len;spi_imx-txfifo0;/* 2. 重新初始化完成量 */reinit_completion(spi_imx-xfer_done);/* 3. 填充TX FIFO并启动传输 */spi_imx_push(spi_imx);// ↓// while (txfifo FIFO_SIZE count 0) {// spi_imx-tx(spi_imx); → 写TX寄存器// txfifo;// }// spi_imx-devtype_data-trigger(spi_imx); → 启动硬件/* 4. 使能TX FIFO空中断 */spi_imx-devtype_data-intctrl(spi_imx,MXC_INT_TE);/* 5. 等待传输完成 */timeoutwait_for_completion_timeout(spi_imx-xfer_done,...);printk([SPI_IMX_TRACE] pio_transfer: EXIT, status%d\n,timeout?0:-ETIMEDOUT);returntimeout?transfer-len:-ETIMEDOUT;}6.3 中断处理核心staticirqreturn_tspi_imx_isr(intirq,void*dev_id){structspi_imx_data*spi_imxdev_id;printk([SPI_IMX_TRACE] ISR: ENTER\n);/* 1. 读取所有RX FIFO中的数据 */while(spi_imx-devtype_data-rx_available(spi_imx)){spi_imx-rx(spi_imx);// → 读RX寄存器// ↓// val readl(spi_imx-base MXC_CSPIRXDATA);// if (spi_imx-rx_buf) {// *(u8 *)spi_imx-rx_buf val;// spi_imx-rx_buf;// }spi_imx-txfifo--;// TX FIFO空出一个位置printk([SPI_IMX_TRACE] ISR: Received byte, txfifo%u\n,spi_imx-txfifo);}/* 2. 如果还有数据要发送 */if(spi_imx-count){spi_imx_push(spi_imx);// 继续填充TX FIFOreturnIRQ_HANDLED;}/* 3. 如果TX FIFO还有数据未发送完 */if(spi_imx-txfifo){/* 使能RX中断等待最后的接收 */spi_imx-devtype_data-intctrl(spi_imx,MXC_INT_RR);returnIRQ_HANDLED;}/* 4. 传输完成 */spi_imx-devtype_data-intctrl(spi_imx,0);// 关闭中断complete(spi_imx-xfer_done);// 唤醒等待线程printk([SPI_IMX_TRACE] ISR: Transfer complete!\n);returnIRQ_HANDLED;}七、推荐的分析步骤步骤1添加probe调试staticintspi_imx_probe(structplatform_device*pdev){printk([SPI_IMX_TRACE] PROBE START \n);// ...原有代码...spi_imx-devtype_dataof_id-data;printk([SPI_IMX_TRACE] probe: devtype%d, intctrl%pS, config%pS\n,spi_imx-devtype_data-devtype,spi_imx-devtype_data-intctrl,spi_imx-devtype_data-config);// ...spi_imx-bitbang.txrx_bufsspi_imx_transfer;printk([SPI_IMX_TRACE] probe: Registered txrx_bufs%pS\n,spi_imx-bitbang.txrx_bufs);retspi_bitbang_start(spi_imx-bitbang);printk([SPI_IMX_TRACE] probe: spi_bitbang_start returned %d\n,ret);printk([SPI_IMX_TRACE] probe: master-transfer_one_message%pS\n,master-transfer_one_message);printk([SPI_IMX_TRACE] PROBE END \n);}步骤2添加传输路径跟踪staticintspi_imx_transfer(structspi_device*spi,structspi_transfer*transfer){printk([SPI_IMX_TRACE] spi_imx_transfer: len%u\n,transfer-len);/* 原有代码 */printk([SPI_IMX_TRACE] spi_imx_transfer: ret%d\n,ret);returnret;}步骤3添加硬件操作跟踪staticvoidmx51_ecspi_trigger(structspi_imx_data*spi_imx){u32 regreadl(spi_imx-baseMX51_ECSPI_CTRL);printk([SPI_IMX_TRACE] trigger: BEFORE ctrl0x%08x\n,reg);if(!spi_imx-usedma)reg|MX51_ECSPI_CTRL_XCH;writel(reg,spi_imx-baseMX51_ECSPI_CTRL);printk([SPI_IMX_TRACE] trigger: AFTER ctrl0x%08x (XCH%d)\n,reg,!!(regMX51_ECSPI_CTRL_XCH));}