IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 系统运维 -> 【Linux驱动开发】SPI -> 正文阅读

[系统运维]【Linux驱动开发】SPI

Linux内核将SPI驱动分成两部分

  • SPI主机驱动:SOC的SPI控制器驱动。半导体厂商编写。
  • SPI设备驱动:具体SPI设备的驱动。SOC使用者编写。

SPI主机驱动

Linux定义spi_master结构体表示SPI主机驱动,include/linux/spi.spi.h。SPI主机驱动申请spi_master,初始化spi_master,向内核注册spi_master。

使用spi_alloc_master申请spi_master。

struct spi_master *spi_alloc_master(struct device *dev, unsigned size)
  • dev:platform_device中的成员变量。
  • size:私有数据private_data大小。
  • 返回值:申请的spi_master。

使用spi_master_put释放spi_master。

void spi_master_put(struct spi_master *master)
  • master:要释放的spi_master。
  • 返回值:无。

使用spi_register_master注册spi_master。

int spi_register_master(struct spi_master *master)
  • master:要注册的spi_master。
  • 返回值:0,成功;负值,失败。

使用spi_unregister_master注销spi_master。

void spi_unregister_master(struct spi_master *master)
  • master:要注销的spi_master。
  • 返回自:无。

SPI设备驱动

Linux使用spi_driver结构体表示spi设备驱动,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;
};

当SPI设备和驱动匹配成功后,执行probe函数。

使用spi_register_driver注册spi_driver。

int spi_register_driver(struct spi_driver *sdrv)
  • sdrv:要注册的spi_driver。
  • 返回值:0,成功;负值,失败。

使用spi_unregister_driver注销spi_driver。

void spi_unregister_driver(struct spi_driver *sdrv)
  • sdrv:要注销的spi_driver。
  • 返回值:无。

SPI设备和驱动匹配

SPI设备和驱动匹配是由SPI总线完成,SPI总线为spi_bus_type,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;
}

struct bus_type spi_bus_type = {
	.name		= "spi",
	.dev_groups	= spi_dev_groups,
	.match		= spi_match_device,
	.uevent		= spi_uevent,
};

SPI设备和驱动的匹配函数为spi_match_device。of_driver_match_device完成设备树设备和驱动匹配,acpi_driver_match_device用于ACPI形式匹配,spi_match_id用于无设备树匹配。

SPI设备数据收发

SPI数据收发步骤

  1. 申请并初始化spi_transfer,设置spi_transfer的tx_buf成员变量、rx_buf成员变量、len成员变量。
  2. 使用spi_message_init初始化spi_message。
  3. 使用spi_message_add_tail将spi_transfer添加到spi_message队列中。
  4. 使用spi_sync或spi_async完成数据同步/异步传输。

Linux定义spi_transfer结构体描述SPI传输信息。

struct spi_transfer {
	const void	*tx_buf;
	void		*rx_buf;
	unsigned	len;

	dma_addr_t	tx_dma;
	dma_addr_t	rx_dma;
	struct sg_table tx_sg;
	struct sg_table rx_sg;

	unsigned	cs_change:1;
	unsigned	tx_nbits:3;
	unsigned	rx_nbits:3;
#define	SPI_NBITS_SINGLE	0x01 /* 1bit transfer */
#define	SPI_NBITS_DUAL		0x02 /* 2bits transfer */
#define	SPI_NBITS_QUAD		0x04 /* 4bits transfer */
	u8		bits_per_word;
	u16		delay_usecs;
	u32		speed_hz;

	struct list_head transfer_list;
};
  • tx_buf:保存要发送的数据。
  • rx_buf:保存接收到的数据。
  • len:数据传输长度。

spi_transfer需要组织成spi_message结构体。

struct spi_message {
	struct list_head	transfers;

	struct spi_device	*spi;

	unsigned		is_dma_mapped:1;

	/* completion is reported through a callback */
	void			(*complete)(void *context);
	void			*context;
	unsigned		frame_length;
	unsigned		actual_length;
	int			status;

	struct list_head	queue;
	void			*state;
};

使用spi_message_init初始化spi_message。

void spi_message_init(struct spi_message *m)
  • m:要初始化的spi_message。
  • 返回值:无。

使用spi_message_add_tail将spi_transfer添加到spi_message队列中。

void spi_message_add_tail(struct spi_transfer *t, struct spi_message *m)
  • t:要添加到队列的spi_transfer。
  • m:spi_transfer要加入的spi_message。
  • 返回值:无。?

使用spi_sync进行同步数据传输。

int spi_sync(struct spi_device *spi, struct spi_message *message)
  • spi:要进行数据传输的spi_device。
  • message:要传输的spi_message。
  • 返回值:无。

使用spi_async进行异步数据传输,异步传输完成后执行complete回调函数。

int spi_async(struct spi_device *spi, struct spi_message *message)

  • spi:要进行数据传输的spi_device。
  • message:要传输的spi_message。
  • 返回值:无。

通过SPI进行数据同步传输,发送和接收示例

/* SPI多字节发送 */
static int spi_send(struct spi_device *spi, u8 *buf, int len)
{
    int ret;
    struct spi_message m;

    struct spi_transfer t = {
        .tx_buf = buf,
        .len = len,
    };

    spi_message_init(&m);
    spi_message_add_tail(t, &m);
    ret = spi_sync(spi, &m);

    return ret;
}
/* SPI多字节接收 */
static int spi_receive(struct spi_device *spi, u8 *buf, int len)
{
    int ret;
    struct spi_message m;

    struct spi_transfer t = {
        .rx_buf = buf,
        .len = len,
    };

    spi_message_init(&m);
    spi_message_add_tail(t, &m);
    ret = spi_sync(spi, &m);

    return ret;
}
  系统运维 最新文章
配置小型公司网络WLAN基本业务(AC通过三层
如何在交付运维过程中建立风险底线意识,提
快速传输大文件,怎么通过网络传大文件给对
从游戏服务端角度分析移动同步(状态同步)
MySQL使用MyCat实现分库分表
如何用DWDM射频光纤技术实现200公里外的站点
国内顺畅下载k8s.gcr.io的镜像
自动化测试appium
ctfshow ssrf
Linux操作系统学习之实用指令(Centos7/8均
上一篇文章      下一篇文章      查看所有文章
加:2022-05-18 18:01:17  更:2022-05-18 18:03:38 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/15 15:26:41-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码