M95080W 是 意法半导体的一款 SPI 接口的 EEPROM,容量大小为 8K bit。如果还没看 M95080W 的数据手册,赶紧去看!
https://blog.csdn.net/lu_embedded/article/details/80682912
硬件连接
i.MX6q 是基于 NXP 四核 ARM Cortex-A9 架构的高性能处理器,它上面有 5 个 SPI 控制器,分别是 ECSPI1~5。在我们这里的测试平台上的硬件连接的情况是这样的:
EEPROM 连接到 ECSPI5(SMARC 接口的 SPI0),具体管脚描述如下:
驱动模型
修改驱动文件
实际上,Linux 内核已经支持 EEPROM 设备了,通常将其注册为 misc 杂项设备。其驱动模板位于 drivers/misc/eeprom 目录中,其中 at24.c 对应的是 I2C 设备,at25.c 对应的是 SPI 设备。M95080W 是 SPI 接口的 EEPROM,所以我们重点关注 at25.c 文件。
drivers/misc/eeprom/at25.c 是比较简单的驱动文件,其中定义了一些操作指令和参数:
#define AT25_WREN 0x06 /* latch the write enable */
#define AT25_WRDI 0x04 /* reset the write enable */
#define AT25_RDSR 0x05 /* read status register */
#define AT25_WRSR 0x01 /* write status register */
#define AT25_READ 0x03 /* read byte(s) */
#define AT25_WRITE 0x02 /* write byte(s)/sector */
#define AT25_SR_nRDY 0x01 /* nRDY = write-in-progress */
#define AT25_SR_WEN 0x02 /* write enable (latched) */
#define AT25_SR_BP0 0x04 /* BP for software writeprotect */
#define AT25_SR_BP1 0x08
#define AT25_SR_WPEN 0x80 /* writeprotect enable */
#define AT25_INSTR_BIT3 0x08 /* Additional address bit in instr */
#define EE_MAXADDRLEN 3 /* 24 bit addresses, up to 2 MBytes */
/* Specs often allow 5 msec for a page write, sometimes 20 msec;
* it's important to recover from write timeouts.
*/
#define EE_TIMEOUT 25
对比 M95080W 的数据手册,发现是兼容的,所以这部分不需要修改。
驱动程序提供了以下接口函数:
at25_bin_read()
at25_bin_write()
at25_ee_read()
at25_ee_write()
at25_mem_read()
at25_mem_write()
at25_np_to_chip()
at25_probe()
at25_remove()
其中驱动注册部分代码是这样的:
static struct spi_driver at25_driver = {
.driver = {
.name = "at25",
.owner = THIS_MODULE,
},
.probe = at25_probe,
.remove = at25_remove,
};
module_spi_driver(at25_driver);
MODULE_DESCRIPTION("Driver for most SPI EEPROMs");
MODULE_AUTHOR("David Brownell");
MODULE_LICENSE("GPL");
MODULE_ALIAS("spi:at25");
并没有设备匹配相关的代码,所以我们要给它加上,如下:
static const struct of_device_id at25_spi_of_match[] = {
{ .compatible = "st,m95080", },
{ },
};
MODULE_DEVICE_TABLE(of, at25_spi_of_match);
static struct spi_driver at25_driver = {
.driver = {
.name = "at25",
.owner = THIS_MODULE,
.of_match_table = at25_spi_of_match,
},
.probe = at25_probe,
.remove = at25_remove,
};
module_spi_driver(at25_driver);
MODULE_DESCRIPTION("Driver for most SPI EEPROMs");
MODULE_AUTHOR("David Brownell");
MODULE_LICENSE("GPL");
MODULE_ALIAS("spi:at25");
在 at25_driver 结构体中的 driver 成员中增加 of_match_table,它是我们在前面定义的一张设备匹配表,其中有一个 .compatible = "st,m95080" 兼容设备。这个名字是我自己取的,待会在设备树里面填写的也要一致。
别忘了还要调用 MODULE_DEVICE_TABLE(of, at25_spi_of_match);,这样就修改好了。
添加设备树节点
参考:Documentation/devicetree/bindings/misc/at25.txt
在 ecspi5 节点中添加子节点 at25,兼容设备 "st,m95080",如下:
&ecspi5 {
fsl,spi-num-chipselects = <1>;
cs-gpios = <&gpio1 17 0>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_ecspi5_1 &pinctrl_ecspi5_cs_0>;
status = "okay";
at25@0 {
compatible = "st,m95080";
spi-max-frequency = <10000000>;
pagesize = <32>;
size = <1024>;
address-width = <16>;
spi-cpha;
spi-cpol;
reg = <0>;
};
};
编译
编译之前先 make menuconfig,确保 CONFIG_EEPROM_AT25 被选上,我这里选择编译进内核。
$ make menuconfig
Device Drivers
|---> Misc devices
|---> EEPROM support
|---> <*> SPI EEPROMs from most vendors
接着编译内核和设备树:
$ source /opt/poky/1.5.3/environment-setup-cortexa9hf-vfp-neon-poky-linux-gnueabi
$ make uImage LOADADDR=0x10008000
$ make imx6q-rom5420-b1.dtb
更新系统!
文件I/O测试
我们可以通过 sysfs 进行简单的读写测试,通过 cat 命令查看 eeprom 的数据,通过 echo 和重定向操作将数据写入 eeprom。
# cat /sys/bus/spi/drivers/at25/spi32764.0/eeprom
# echo "hello" > /sys/bus/spi/drivers/at25/spi32764.0/eeprom
然后断电重启,再 cat 下看看“hello”还在不在吧!
测试程序
放在 GitHub 了: https://github.com/luhuadong/Linux-programming/blob/master/driver/eeprom/test/eeprom_go.c
---------------------
作者:阿基米东
来源:CSDN
原文:https://blog.csdn.net/lu_embedded/article/details/80684042
版权声明:本文为博主原创文章,转载请附上博文链接!