Linux SPI/QSPI nor flash相关驱动代码
对于 spi 接口,本身是可以接很多种类的外设的,比如用于接带有SPI通信协议的芯片,通常是将其作为字符设备类型注册。
对于接SPI/QSPI Flash时,又通常作为mtd设备(memory technology device内存技术设备)。MTD的主要目的是为了使新的memory设备的驱动更加简单,为此它在硬件和上层之间提供了一个抽象的接口,主要是读写擦接口。
在芯片厂家设计接口时,有时会把接SPI/QSPI flash接口的单独封装成独立于SPI的专用接口,这就会出现两种情况外设接的是Flash。造就了在SPI 控制器(master)侧的驱动放的位置不一样。
1. 通用SPI 接口,通常通过drivers/mtd/devices/m25p80.c 注册mtd设备
2.SPI/QSPI flash 专用接口控制器
通用SPI 接口文件关系
参考:https://blog.csdn.net/kickxxx/article/details/68924170
1. drivers/spi/spi.c: 是linux spi通用框架代码, 向下适配ti mcspi以及ti qspi控制器驱动.
2. drivers/spi/spi-ti-qspi.c: TI qspi主控器驱动, 不同平台使用不同的主控驱动
3. drivers/mtd/devices/m25p80.c: m25p80.c和spi-nor.c都是linux spi nor驱动框架的一部分
4. drivers/mtd/spi-nor/spi-nor.c: m25p80.c和spi-nor.c都是linux spi nor驱动框架的一部分
SPI/QSPI flash 专用接口文件关系
1. drivers/mtd/spi-nor/fsl-quadspi.c: fsl qspi专用flash主控制器驱动,不同平台使用不同的主控制器驱动。mtd设备注册也是在这主流程中。
2. drivers/mtd/spi-nor/spi-nor.c: 提供通用扫描接口,并封装向上mtd层提供的spi-nor的读写擦接口
系统框架
mtd : mtd->_read,
spi-nor: spi_nor_read
控制器:nor->read = fsl_qspi_read
spi-nor.c
从架构图可以看出spi-nor是简单的粘合层, 把mtd调用转换为m25p80接口. spi-nor还包含了qspi芯片检测, 通过芯片ID, 确定spi nor的参数:sector size, nsectors, pagesize, flags.
spi-nor驱动适配多种spi nor flash, 这些flash的驱动层代码差异, 由flash_info的几个参数表示.
spi-nor.c为mtd子系统服务, 为mtd层提供如下几个接口:
- spi_nor_write
- spi_nor_erase
- spi_nor_read
spi_nor_scan调用spi_nor_read_id从chip获取ID, 根据chip ID得到该芯片的flash_info
1. 设置mtd_info的type, writesize, size等参数
2. 设置mtd_info的_erase, _read, _write回调函数
3. 设置mtd_info 的erasesize驱动分析
一个现实的设备通常都需要挂接在一种总线上,比较常见的总线有USB、PCI总线等。但是,在嵌入式系统里面,SoC系统中集成的独立的外设控制器、挂接在SoC内存空间的外设却不依附与此类总线。基于这样的背景下,2.6内核加入了platform虚拟总线。platform机制将设备本身的资源注册进内核,由内核统一管理,在驱动程序使用这些资源时使用统一的接口。platform总线对加入到该总线的设备和驱动分别封装了两个结构体——platform_device和platform_driver。并且提供了对应的注册函数
SPI控制器依附platform bus,驱动采用platform driver描述。
SPI 设备(SPI Flash)依附SPI 总线,是实体存在的总线机制,对应驱动采用spi driver描述。
Platform总线、设备、 驱动
platform总线注册由内核管理,平台设备platform_device描述的SPI控制器的信息(数据),platform_driver对应提供控制器的使用方法(策略)支持。
之前的内核,platform_device描述一般如下
static struct platform_device qt2410_cs89x0 = {
.name = "cirrus-cs89x0",
.num_resources = ARRAY_SIZE(qt2410_cs89x0_resources),
.resource = qt2410_cs89x0_resources,
};
通过以下两个函数中之一注册设备
int platform_device_register(struct platform_device *);
int platform_add_devices(struct platform_device **, int); //针对的是1个或多个
支持dts的内核版本,platform_device描述直接在dts中描述,有内核解析dts时统一生成platform_device。
在初始化先后顺序上,从左到右是:平台总线 --》平台设备 --》平台驱动。实际上所有的总线类型,平台总线总是要较早初始化的。
更多推荐
所有评论(0)