M95080W 是 意法半导体的一款 SPI 接口的 EEPROM,容量大小为 8K bit。如果还没看 M95080W 的数据手册,赶紧去看! ​


硬件连接

  i.MX6q 是基于 NXP 四核 ARM Cortex-A9 架构的高性能处理器,它上面有 5 个 SPI 控制器,分别是 ECSPI1~5。在我们这里的测试平台上的硬件连接的情况是这样的:


Linux 驱动 SPI EEPROM(M95080W)_SPI

  EEPROM 连接到 ECSPI5(SMARC 接口的 SPI0),具体管脚描述如下:


Linux 驱动 SPI EEPROM(M95080W)_EEPROM_02

驱动模型


Linux 驱动 SPI EEPROM(M95080W)_Linux_03

修改驱动文件

  实际上,Linux 内核已经支持 EEPROM 设备了,通常将其注册为 misc 杂项设备。其驱动模板位于 drivers/misc/eeprom 目录中,其中 at24.c 对应的是 I2C 设备,at25.c 对应的是 SPI 设备。M95080W 是 SPI 接口的 EEPROM,所以我们重点关注 at25.c 文件。
  drivers/misc/eeprom/at25.c

#define
#define
#define
#define
#define
#define

#define
#define
#define
#define
#define

#define

#define

/* Specs often allow 5 msec for a page write, sometimes 20 msec;
* it's important to recover from write timeouts.
*/
#define

  对比 ​​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​