kernel-4.14/drivers/spi/spi.c
static int __init spi_init(void)
{
int status;
buf = kmalloc(SPI_BUFSIZ, GFP_KERNEL);
if (!buf) {
status = -ENOMEM;
goto err0;
}
// 创建 /sys/bus/spi 节点
status = bus_register(&spi_bus_type);
if (status < 0)
goto err1;
//创建 /sys/class/spi_master 节点
status = class_register(&spi_master_class);
if (status < 0)
goto err2;
if (IS_ENABLED(CONFIG_SPI_SLAVE)) {
status = class_register(&spi_slave_class);
if (status < 0)
goto err3;
}
......
}
在这里创建了 SPI 总线,创建 /sys/bus/spi 节点和 /sys/class/spi_master 节点。
重要数据结构:
spi_device
spi_driver
spi_board_info
spi_controller/spi_master
spi_transfer
spi_message
重要 API
spi_message_init
spi_message_add_tail
spi_sync
spi_async
spi_write
spi_read
接下来详细解析结构体和API,只讲解重点部分,完整解析请参考官方文档
https://www.kernel.org/doc/html/v4.14//driver-api/spi.html
只有熟悉每个结构体存储的是什么东西,才能真正搞懂 SPI 模块。
spi_master/spi_controller:描述一个 spi 主机设备
struct spi_master {
//Linux 驱动模型中的设备
struct device dev;
//此 spi_master 设备在全局 spi_master 链表中的节点
struct list_head list;
//此 spi_master 编号
s16 bus_num;
//此 spi_master 支持的片选信号数量
u16 num_chipselect;
//dma 地址对齐
u16 dma_alignment;
//此 spi_master 支持传输的 mode
u16 mode_bits;
u32 bits_per_word_mask;
/* limits on transfer speed */
u32 min_speed_hz;
u32 max_speed_hz;
/* other constraints relevant to this driver */
u16 flags;
/* lock and mutex for SPI bus locking */
spinlock_t bus_lock_spinlock;//总线自旋锁
struct mutex bus_lock_mutex;//总线互斥锁
//总线是否处于 lock 状态
bool bus_lock_flag;
//准备传输,设置传输的参数
int (*setup)(struct spi_device *spi);
//传输数据
int (*transfer)(struct spi_device *spi,
struct spi_message *mesg);
// 设备 release 时的清除工作
void (*cleanup)(struct spi_device *spi);
bool (*can_dma)(struct spi_master *master,
struct spi_device *spi,
struct spi_transfer *xfer);
bool queued;//是否采用系统的序列化传输
struct kthread_worker kworker;//序列化传输时的线程 worker
struct task_struct *kworker_task;//序列化传输的线程
struct kthread_work pump_messages;//序列化传输时的处理函数
spinlock_t queue_lock;//序列化传输时的queue_lock
struct list_head queue;//序列化传输时的 msg 队列头
struct spi_message *cur_msg;//序列化传输时当前的 msg
bool idling;
bool busy;//序列化传输时线程是否处于busy状态
bool running;//序列化传输时线程是否在运行
bool rt;//是否实时传输
......
int (*prepare_transfer_hardware)(struct spi_master *master);
//一个 msg 的传输实现
int (*transfer_one_message)(struct spi_master *master,
struct spi_message *mesg);
......
/* gpio chip select */
int *cs_gpios;
......
};
spi_device:描述一个 spi 从机设备
struct spi_device {
//Linux驱动模型中的设备
struct device dev;
struct spi_master *master;//设备所连接的 spi 主机设备
u32 max_speed_hz;//该设备最大传输速率
u8 chip_select;//CS片选信号编号
u8 bits_per_word;//每次传输长度
u16 mode;//传输模式
......
int irq;//软件中断号
void *controller_state;//控制器状态
void *controller_data;//控制参数
char modalias[SPI_NAME_SIZE];//设备名称
//CS 片选信号对应的 GPIO number
int cs_gpio; /* chip select gpio */
/* the statistics */
struct spi_statistics statistics;
};
spi_driver:描述一个 spi 设备驱动
struct spi_driver {
//此driver所支持的 spi 设备 list
const struct spi_device_id *id_table;
int (*probe)(struct spi_device *spi);
int (*remove)(struct spi_device *spi);
//系统 shutdown 时的回调函数
void (*shutdown)(struct spi_device *spi);
struct device_driver driver;
};
spi_board_info:描述一个 spi 从机设备板级信息,无设备树时使用
struct spi_board_info {
//设备名称
char modalias[SPI_NAME_SIZE];
const void *platform_data;//设备的平台数据
void *controller_data;//设备的控制器数据
int irq;//设备的中断号
u32 max_speed_hz;//设备支持的最大速率
u16 bus_num;//设备连接的 spi 总线编号
u16 chip_select;//设备连接的 CS 信号编号
u16 mode;//设备使用的传输 mode
};
spi_transfer:描述 spi 传输的具体数据
struct spi_transfer {
const void *tx_buf;//spi_transfer 的发送 buf
void *rx_buf;//spi_transfer 的接收 buf
unsigned len;//spi_transfer 发送和接收的长度
dma_addr_t tx_dma;//tx_buf 对应的 dma 地址
dma_addr_t rx_dma;//rx_buf 对应的 dma 地址
struct sg_table tx_sg;
struct sg_table rx_sg;
//spi_transfer传输完成后是否要改变 CS 片选信号
unsigned cs_change:1;
unsigned tx_nbits:3;
unsigned rx_nbits:3;
......
u8 bits_per_word;//spi_transfer 中一个 word 占的bits
u16 delay_usecs;//两个 spi_transfer 直接的等待延迟
u32 speed_hz;//spi_transfer 的传输速率
struct list_head transfer_list;//spi_transfer挂载到的 message 节点
};
spi_message:描述一次 spi 传输的信息
struct spi_message {
//挂载在此 msg 上的 transfer 链表头
struct list_head transfers;
//此 msg 需要通信的 spi 从机设备
struct spi_device *spi;
//所使用的地址是否是 dma 地址
unsigned is_dma_mapped:1;
//msg 发送完成后的处理函数
void (*complete)(void *context);
void *context;//complete函数的参数
unsigned frame_length;
unsigned actual_length;//此 msg 实际成功发送的字节数
int status;//此 msg 的发送状态,0:成功,负数,失败
struct list_head queue;//此 msg 在所有 msg 中的链表节点
void *state;//此 msg 的私有数据
};
全部0条评论
快来发表一下你的评论吧 !