SPI 驱动用 spi_driver 结构体注册,of_match_table 匹配设备树;probe 里初始化硬件、创建字符设备或用 spidev;收发用 spi_sync/spi_write/spi_read(同步)或 spi_async(异步),spi_transfer 描述每段传输;用户态通过 /dev/spidevX.Y 用 ioctl 读写,或驱动创建 sysfs/cdev。
本文概述
SPI 驱动是 Linux 常见驱动类型,面试常考:spi_driver、probe、spi_sync、spidev。回答要给驱动框架和收发函数。
核心要点
spi_driver 注册:driver.name、probe、remove、of_match_table(设备树匹配)
probe:spi_setup 设置模式/速率/位宽,初始化硬件,注册 cdev/sysfs
收发:spi_sync(同步阻塞)、spi_async(异步回调)、spi_write/spi_read(简单封装)
spi_transfer:tx_buf/rx_buf、len、speed_hz、bits_per_word、cs_change
用户态:/dev/spidevX.Y(spidev 驱动,ioctl SPI_IOC_MESSAGE)或驱动自建 cdev/sysfs

面试官考察点
Linux 驱动基础题。面试官看你是否写过 SPI 驱动。重点听:spi_driver、probe、spi_transfer。
回答思路
给 spi_driver 结构、probe 流程、收发函数、用户态访问。
参考回答
spi_driver 结构。
static const struct of_device_id my_spi_of_match[] = {
{ .compatible = "vendor,myspichip" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, my_spi_of_match);
static struct spi_driver my_spi_driver = {
.driver = {
.name = "my_spi_chip",
.of_match_table = my_spi_of_match,
},
.probe = my_spi_probe,
.remove = my_spi_remove,
};
module_spi_driver(my_spi_driver);
probe 函数流程。
设置 SPI 模式:spi->mode = SPI_MODE_0(CPOL=0,CPHA=0);
设置最大速率:spi->max_speed_hz = 10000000(10MHz);
设置位宽:spi->bits_per_word = 8;
调用 spi_setup(spi) 生效;
读设备 ID 确认硬件存在;
分配私有数据,注册字符设备或 sysfs;
spi_set_drvdata(spi, data) 保存。
static int my_spi_probe(struct spi_device *spi){
struct my_data *data;
spi->mode = SPI_MODE_0;
spi->max_speed_hz = 10000000;
spi->bits_per_word = 8;
spi_setup(spi);
data = devm_kzalloc(&spi->dev, sizeof(*data), GFP_KERNEL);
data->spi = spi;
spi_set_drvdata(spi, data);
// 注册 cdev/sysfs
return 0;
}
SPI 收发函数。
| 函数 | 用途 |
|---|---|
| spi_write(spi, buf, len) | 只写(半双工,MOSI) |
| spi_read(spi, buf, len) | 只读(发 dummy 字节,读 MISO) |
| spi_sync(spi, &msg) | 通用同步传输,支持多 transfer |
| spi_async(spi, &msg, callback) | 异步传输,完成后回调 |
| spi_write_then_read(spi, tx, txlen, rx, rxlen) | 先写后读(常用,读寄存器) |
// 读寄存器 reg:先发 reg 地址,再读数据
u8 tx[2] = {reg | 0x80, 0}; // 读标志位
u8 rx[2];
struct spi_transfer t = {
.tx_buf = tx, .rx_buf = rx,
.len = 2, .speed_hz = 10000000,
};
struct spi_message m;
spi_message_init(&m);
spi_message_add_tail(&t, &m);
spi_sync(spi, &m);
// rx[1] 是读到的数据
用户态访问。
spidev:内核配置 CONFIG_SPI_SPIDEV,设备树里 compatible="spidev",生成 /dev/spidevX.Y;用户态 open + ioctl(SPI_IOC_MESSAGE) 收发;
自建字符设备:驱动注册 cdev,用户态 read/write/ioctl,适合复杂协议;
sysfs:驱动在 /sys/bus/spi/devices/ 下创建属性,cat/echo 读写,适合简单配置;
spidev_test:内核工具 tools/spi/spidev_test.c,测试 SPI 通信。
注意。
SPI 是全双工,spi_sync 收发同时进行,tx_buf 和 rx_buf 可以不同;
多设备共享总线时,CS 由内核管理(spi_transfer.cs_change);
SPI 没有 ACK,出错不重传,靠校验或重试;
高速 SPI(>10MHz)注意 PCB 走线和信号完整性,可能需要用 DMA。
面试官可能追问
常见失分表达
准备动作
核心关键词
相关文章

负压电源怎么产生?电荷泵与反压电路怎么选?电源工程师面试
2026-09-03 13:53:06
Linux文件权限755、644怎么理解?脚本报Permission denied怎么排查?
2026-10-31 15:43:20
嵌入式Linux面试:DMA传完数据CPU却读到旧值?Cache一致性要这样排
2026-10-17 15:37:27
PCB差分对走线设计要点与等长绕线方法 - PCB设计面试题详解
2026-08-18 21:06:22
FPGA时序约束怎么写?create_clock、set_input_delay、setup/hold怎么分析?FPGA面试
2026-10-07 10:02:54






