目录
一、介绍
linux内核版本:3.14-xilinx
具体使用和查看的代码文件主要有如下几个:
/drivers/mtd/Mtdchar.c --MTD字符设备
/drivers/mtd/Mtdblock.c --MTD块设备
/drivers/mtd/Mtdcore.c --MTD原始设备
/drivers/mtd/Devices/M25p80.c --SPI Flash设备驱动
/drivers/spi/Spi-zynq-qspi.c --QSPI控制器驱动
/drivers/spi/Spi.c -- SPI总线核或者通用API
1.1 mtd子系统结构
*设备节点层:MTD框架可以在/dev下创建字符设备节点(主设备号90)以及块设备节点(主设备号31), 用户通过访问此设备节点即可访问MTD字符设备或块设备。
*MTD设备层: 基于MTD原始设备, Linux在这一层次定义出了MTD字符设备和块设备, 字符设备在mtdchar.c中实现, 块设备则是通过结构mtdblk_dev来描述,"/drivers/mtd/mtdchar.c"文件实现了MTD字符设备接口; "/drivers/mtd/mtdblock.c"文件实现了MTD块设备接口
*MTD原始设备层: 由MTD原始设备的通用代码+特定的Flash数据组成。mtd_info、mtd_part、mtd_partition以及mtd_partitions等对象及其操作方法就属于这一层,对应的文件是"drivers/mtd/mtdcore.c"。类似于i2c驱动框架中的核心层。
*硬件驱动层: 内核将常用的flash操作都已经在这个层次实现, 驱动开发只需要将相应的设备信息添加进去即可, 比如nor flash的芯片驱动位于"drivers/mtd/chips/", nand flash位于"drivers/mtd/nand/
引用:Linux MTD子系统 _从模型分析到Flash驱动模板 - Abnor - 博客园
1.2 SPI子系统框架
SPI子系统采用分层分离的思想,大体框架如下所示:
其中,客户驱动对应于/drivers/mtd/Devices/M25p80.c
SPI core对应于/drivers/spi/Spi.c
控制器驱动对应于/drivers/spi/Spi-zynq-qspi.c
二、各个模块(函数)调用依赖关系介绍
熟悉各个函数的调用关系,先按照mtd_read这一个操作以此往下查看。
首先,在mtdchar.c中有mtdchar设备的初始化函数init_mtdchar()。其中就注册了mtd设备的操作函数mtd_fops。
接下来进入mtdchar_read()函数,获取该函数的调用关系如下:
mtdchar_read() ---(mtdchar.c)
mtd_read() ---(mtdcore.c)
mtd->_read() ---(mtdcore.c)
flash->mtd._read = m25p80_read_ext --- (M25p80.c m25p_probe() )
m25p80_read_ext() ---( M25p80.c)
m25p80_read() ---( M25p80.c)
spi_sync() ---(Spi.c)
master->transfer() ---( Spi.c)
在spi_register_master()中有
在注册spi master的时候,如果没有指定master->transfer(),则在spi_master_initialize_queue()中对master->transfer()以及对master-> transfer_one_message进行初始化。
在函数spi_queued_transfer()中,我们发现spi数据是交给内核线程进行处理的,内核线程为master->pump_message,如下
在上一步中的spi_master_initialize_queue(),对master->transfer()进行初始化后,接着调用了spi_init_queue()这个函数,在该函数中发现有对master->pump_message进行初始化。如下:
接着,进入内核线程spi_pump_messages()继续。发现在该线程中,通过调用master->fn的几个函数最终完成数据发送。如下:
到这里,spi总线的工作就完成了。那么master->fn这些函数哪里注册的,还有spi_register_master()是哪里调用的?
最后,在Spi-zynq-qspi.c中的zynq_qspi_probe()中发现了这些函数的注册。如下:
这样,函数的调用关系就到此为止了。至于数据是怎样进行传递的,就需要注意各个模块、设备以及驱动的结构体了,里面有用于数据传递的指针定义。
总结:mtd设备读写是调用的Flash设备驱动(具体的芯片驱动,例如m25p80)的读写函数,一般在驱动初始化时将设备的读写函数注册到mtd设备,设备驱动使用SPI总线向外发送数据,而SPI总线在接收到读写请求时,通过一个内核线程对数据进行处理,在线程中会调用SPI master的读写函数, SPI master的读写操作函数在SPI控制器驱动中进行注册。
注:在SPI收发数据时,为什么会使用到内核线程(kthread_worker与kthread_work)以及线程同步(completion),是由于SPI控制器在进行数据传输时使用的中断进行处理,例如发送完成、接收到数据时都会进入中断。