SPI驱动框架简介

SPI驱动框架简介

SPI框架图

在这里插入图片描述

  • SPI核心层

    提供SPI控制器驱动和 设备驱动 的注册方法、注销方法、SPI通信硬件无关接口

  • SPI主机驱动

    主要包含SPI硬件体系结构中适配器(spi控制器)的控制,用于产生SPI 读写时序

    主要数据结构:spi_master(spi_controller)

  • SPI设备驱动

    通过SPI主机驱动与CPU交换数据

    主要数据结构:spi_device和spi_driver

核心数据结构
spi_master

include/linux/spi/spi.h

#define spi_master			spi_controller
spi_controller

include/linux/spi/spi.h

struct spi_controller {
	struct device	dev;
	...
	struct list_head list;
	s16			bus_num;   //SPI控制器编号
	u16			num_chipselect;  //SPI片选控制器数量
	...
	struct spi_message		*cur_msg;  
	...
	int			(*setup)(struct spi_device *spi);
	int			(*transfer)(struct spi_device *spi,
						struct spi_message *mesg);
	void		(*cleanup)(struct spi_device *spi);
	struct kthread_worker		kworker;
	struct task_struct		*kworker_task;
	struct kthread_work		pump_messages;
	struct list_head		queue;
	struct spi_message		*cur_msg;
	
	...
	int (*transfer_one)(struct spi_controller *ctlr, struct spi_device *spi,struct spi_transfer *transfer);
	int (*prepare_transfer_hardware)(struct spi_controller *ctlr);
	int (*transfer_one_message)(struct spi_controller *ctlr,struct spi_message *mesg);
	void (*set_cs)(struct spi_device *spi, bool enable);
	...
	int			*cs_gpios;
}
  • list:链表节点,芯片可能有多个spi控制器

  • bus_num:spi控制器编号

  • num_chipselect:片选信号的个数

  • cur_msg:当前正带处理的消息队列

  • transfer :用于把数据加入控制器的消息链表中

  • cleanup:当spi_master被释放的时候,完成清理工作

  • kworker:内核线程工人,spi可以使用异步传输方式发送数据

  • pump_messages:具体传输工作

  • queue:所有等待传输的消息队列挂在该链表下

  • transfer_one_message:发送一个spi消息,类似IIC适配器里的algo->master_xfer,产生spi通信时序

  • 相关API

    • int spi_register_master(struct spi_master *master)

      注册一个spi_controller

    • void spi_unregister_master(struct spi_master *master)

      注销一个spi_controller

spi_device

include/linux/spi/spi.h

struct spi_device {
	struct device		dev;
	struct spi_controller	*controller;
	struct spi_controller	*master;	/* compatibility layer */
	u32			max_speed_hz;
	u8			chip_select;
	u8			bits_per_word;
	u16			mode;
#define	SPI_CPHA	0x01			/* clock phase */
#define	SPI_CPOL	0x02			/* clock polarity */
#define	SPI_MODE_0	(0|0)			/* (original MicroWire) */
#define	SPI_MODE_1	(0|SPI_CPHA)
#define	SPI_MODE_2	(SPI_CPOL|0)
#define	SPI_MODE_3	(SPI_CPOL|SPI_CPHA)
#define	SPI_CS_HIGH	0x04			/* chipselect active high? */
#define	SPI_LSB_FIRST	0x08			/* per-word bits-on-wire */
#define	SPI_3WIRE	0x10			/* SI/SO signals shared */
#define	SPI_LOOP	0x20			/* loopback mode */
#define	SPI_NO_CS	0x40			/* 1 dev/bus, no chipselect */
#define	SPI_READY	0x80			/* slave pulls low to pause */
#define	SPI_TX_DUAL	0x100			/* transmit with 2 wires */
#define	SPI_TX_QUAD	0x200			/* transmit with 4 wires */
#define	SPI_RX_DUAL	0x400			/* receive with 2 wires */
#define	SPI_RX_QUAD	0x800			/* receive with 4 wires */
...
	char			modalias[SPI_NAME_SIZE];
...
}
spi_driver

include/linux/spi/spi.h

struct spi_driver {
	const struct spi_device_id *id_table;
	int			(*probe)(struct spi_device *spi);
	int			(*remove)(struct spi_device *spi);
	void			(*shutdown)(struct spi_device *spi);
	struct device_driver	driver;
};
  • probe:spi设备和spi驱动匹配后,回调该函数指针

  • 相关API:

    • int spi_register_driver(struct spi_driver *sdrv)

      注册一个spi驱动

    • void spi_unregister_driver(struct spi_driver *sdrv)

      注册一个spi驱动

spi 总线注册

drivers/spi/spi.c

static int __init spi_init(void)
{
	int	status;
	...
	status = bus_register(&spi_bus_type);
	...
	status = class_register(&spi_master_class);
	...
}
  • sys/bus/spi
  • sys/class/spi_master
spi总线定义
struct bus_type spi_bus_type = {
	.name		= "spi",
	.dev_groups	= spi_dev_groups,
	.match		= spi_match_device,
	.uevent		= spi_uevent,
};
spi_match_device()函数

drivers/spi/spi.c

static int spi_match_device(struct device *dev, struct device_driver *drv)
{
	const struct spi_device	*spi = to_spi_device(dev);
	const struct spi_driver	*sdrv = to_spi_driver(drv);

	/* Attempt an OF style match */
	if (of_driver_match_device(dev, drv))
		return 1;

	/* Then try ACPI */
	if (acpi_driver_match_device(dev, drv))
		return 1;

	if (sdrv->id_table)
		return !!spi_match_id(sdrv->id_table, spi);

	return strcmp(spi->modalias, drv->name) == 0;
}
spi控制器驱动
设备树节点

arch/arm/boot/dts/imx6ull.dtsi

4个spi控制器节点

ecspi3: ecspi@2010000 {
					#address-cells = <1>;
					#size-cells = <0>;
					compatible = "fsl,imx6ul-ecspi", "fsl,imx51-ecspi";
					reg = <0x2010000 0x4000>;
					interrupts = <GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>;
					clocks = <&clks IMX6UL_CLK_ECSPI3>,
						 <&clks IMX6UL_CLK_ECSPI3>;
					clock-names = "ipg", "per";
					dmas = <&sdma 7 7 1>, <&sdma 8 7 2>;
					dma-names = "rx", "tx";
					status = "disabled";
				};
module_platform_driver()宏

include/linux/platform_device.h

#define module_platform_driver(__platform_driver) \
	module_driver(__platform_driver, platform_driver_register, \
			platform_driver_unregister)
module_driver()宏

include/linux/device.h

#define module_driver(__driver, __register, __unregister, ...) \
static int __init __driver##_init(void) \
{ \
	return __register(&(__driver) , ##__VA_ARGS__); \
} \
module_init(__driver##_init); \
  • __driver:spi_imx_driver

  • __register:platform_driver_register

  • __unregister:platform_driver_unregister

  • ##_VA_ARGS_:可变参数

module_platform_driver(spi_imx_driver)
static int __init spi_imx_driver_init(void) \
{ \
	return platform_driver_register(&(spi_imx_driver) , ##__VA_ARGS__); \
} \
module_init(spi_imx_driver_init); \
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值