Linux之 SPI 驱动框架- spi-mem 框架

一、框架变更的历程

1.1 旧框架图

1.2 新框架图

那么问题来了, 为什么要开发新的 SPI 存储器接口?

有了这个新的框架, SPI NOR 和SPI NAND 都可以基于相同的SPI控制器驱动进行支持了。m25p80 驱动将被修改成,使用spi-mem 接口,取代具有局限性的spi_flash_read() 接口。目前, 我们仍然有专用的SPI NOR控制器,但是最终是移除他们,并将他们移植为 drivers/spi/ 下 的普通SPI控制器驱动。

spi-mem framework

        linux 中spi-mem 的核心代码在 drivers/spi/spi-mem.c , 该框架提供给spi 存储控制器驱动的api 。

注:4.x版本内核后,spi-nand就已经使用spi-mem framework了。但是spi-nor直到5.x版本才使用spi-mem驱动。具体版本未作考证,所以选取了教新得到5.14.9版本内核来进行代码分析。

二、重要的数据结构

2.1 struct spi_mem
  spi-mem本质是一个spi总线从设备驱动,使用struct spi_mem来描述一个spi存储设备。

struct spi_mem {
    struct spi_device *spi;
    void *drvpriv;
    const char *name;
};

  • spi:底层的spi device,可以看出spi_mem是对spi_device的简单封装。
  • drvpriv:spi_mem_driver的私有数据
  • name:该spi-mem的名字
     

2.2 

struct spi_mem_op

  该结构体表示一次对spi存储器的操作。提供给上层存储器驱动使用。

struct spi_mem_op {
	struct {
		u8 nbytes;
		u8 buswidth;
		u8 dtr : 1;
		u16 opcode;
	} cmd;

	struct {
		u8 nbytes;
		u8 buswidth;
		u8 dtr : 1;
		u64 val;
	} addr;

	struct {
		u8 nbytes;
		u8 buswidth;
		u8 dtr : 1;
	} dummy;

	struct {
		u8 buswidth;
		u8 dtr : 1;
		enum spi_mem_data_dir dir;
		unsigned int nbytes;
		union {
			void *in;
			const void *out;
		} buf;
	} data;
};

通常spi存储器的操作,包括opcode(cmd)、addr、dummy、data。注意,buswidth代表single、dual、quad传输。

2.3 spi_controller_mem_ops

故名意思,提供给spi_controller注册使用的回调函数集。一个希望优化SPI存储器操作的spi控制器,都可以实现该回调函数集。

struct spi_controller_mem_ops {
	int (*adjust_op_size)(struct spi_mem *mem, struct spi_mem_op *op);
	bool (*supports_op)(struct spi_mem *mem,
			    const struct spi_mem_op *op);
	int (*exec_op)(struct spi_mem *mem,
		       const struct spi_mem_op *op);
	const char *(*get_name)(struct spi_mem *mem);
	int (*dirmap_create)(struct spi_mem_dirmap_desc *desc);
	void (*dirmap_destroy)(struct spi_mem_dirmap_desc *desc);
	ssize_t (*dirmap_read)(struct spi_mem_dirmap_desc *desc,
			       u64 offs, size_t len, void *buf);
	ssize_t (*dirmap_write)(struct spi_mem_dirmap_desc *desc,
				u64 offs, size_t len, const void *buf);
	int (*poll_status)(struct spi_mem *mem,
			   const struct spi_mem_op *op,
			   u16 mask, u16 match,
			   unsigned long initial_delay_us,
			   unsigned long polling_rate_us,
			   unsigned long timeout_ms);
};
  • adjust_op_size:调整存储器操作的数据传输大小,以符合对齐要求和最大FIFO大小的约束。用于校正单次spi存储器传输数据长度。如单次要求读取1024字节,但是控制器只支持单次512字节传输,那么在此回调中,就需要将spi_mem_op->data.nbytes限制到512字节。spi存储器的core层,会自动将分包后,后续数据的读取地址增加。如果回调中没实现,则使用spi-mem驱动框架中默认的校正接口。代码如下:
int spi_mem_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op)
{
	struct spi_controller *ctlr = mem->spi->controller;
	size_t len;

	if (ctlr->mem_ops && ctlr->mem_ops->
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值