W25Q80DV 是 Winbond 的一款 SPI Flash,容量大小为 8M bit。如果还没看 W25Q80DV 的数据手册,赶紧去看!
本文描述的是在 i.MX6q 硬件平台上添加 W25Q80DV 芯片(SPI 设备),Linux 内核版本为 kernel-3.10.17,采用 DeviceTree 描述硬件连接信息。
##硬件连接
i.MX6q 是基于 NXP 四核 ARM Cortex-A9 架构的高性能处理器,它上面有 5 个 SPI 控制器,分别是 ECSPI1~5。在我们这里的测试平台上的硬件连接的情况是这样的:
管脚描述:
##驱动模型
##MTD
MTD设备分为四层(从设备节点直到底层硬件驱动),这四层从上到下依次是:
- 设备节点
- MTD设备层
- MTD原始设备层
- 硬件驱动层
MTD 子系统实现了 SPI flash 芯片驱动程序,其驱动 Demo 为:
drivers/mtd/devices/mtd_dataflash.c
drivers/mtd/devices/m25p80.c
##驱动文件
对于我们这里的 W25Q80DV 设备,重点关注的驱动文件是:
drivers/mtd/devices/m25p80.c
其主要代码框架如下:
通读 m25p80.c 驱动代码,我们可以找出大概的脉络。首先是通过 module_spi_driver
函数注册 m25p80_driver 驱动,其中实现了 probe 和 remove 函数,分别是 m25p_probe
和 m25p_remove
。并且填写了一张名为 m25p_ids 的兼容设备表,通过查看 W25Q80DV 的数据手册,JEDEC 设备 ID 为 0xef4014,也就是对应 m25p_ids 中的 w25q80bl。
其中 INFO 是一个宏定义,其作用是将设备参数填写到内部的 flash_info 结构体实例中,在设备匹配成功后使用。
在 m25p_probe
函数中指定了 m25p80_read
、m25p80_write
和 m25p80_erase
等文件操作函数,当应用程序使用 read、write、ioctl 等接口操作时最终会调用到这里。
额,那 open 和 close 函数呢?
还记得我们把 W25Q80DV 注册成 MTD 设备了嘛,所以另外一些操作函数在 drivers/mtd/mtdchar.c 中定义。实际上,它不仅有 mtdchar_open
、mtdchar_close
等函数,还有 mtdchar_read
和 mtdchar_write
函数,而它们会调用 m25p80.c 中的 m25p80_read
和 m25p80_write
函数。
##设备树节点
接下来要根据实际的硬件连接情况修改设备树文件,不用担心不会写,因为芯片厂商一定会提供参考信息的,比如这里的 SPI Flash,参考以下文件:
Documentation/devicetree/bindings/mtd/m25p80.txt
我这里的 W25Q80DV 连接到 i.MX6Q 的 ECSPI4,具体如下:
##编译&验证
重新编译 image 和 dtb:
更新系统后重新启动,进入 shell。输入命令 dmesg | grep spi
,看到如下内容则说明内核已经探测到 w25q80bl 设备,把设备和驱动程序匹配上了。
查看设备文件:
可以看到多了 /dev/mtd1 之类的设备节点,其中 /dev/mtd1 是字符设备,/dev/mtdblock1 是块设备,/dev/mtd1ro 是只读字符设备。
##挂载 MTD 设备挂载
因为我们把 SPI Flash 注册成 MTD 设备了,因此,我们可以通过 MTD 子系统和文件系统对其进行操作。
首先对 Flash 进行格式化,然后挂载,接着就可以通过文件系统操作:
然后断电重启,看看文件及其内容是否还在,并且与断电前一致。
##“读写擦”测试程序
除了通过文件系统操作 W25Q80DV 设备外,也可以直接打开 /dev/mtd1 设备节点对其进行操作。
测试程序有点长,我放在 GitHub 上了,大家可以参考下:
https://github.com/luhuadong/Linux-programming/blob/master/driver/mtd/test/mtd_go.c