SPI驱动(三) -- SPI设备树处理过程
文章目录
- 参考资料:
- 一、SPI设备树节点构成
- 二、SPI设备树示例
- 2.1 SPI控制器节点属性
- 2.2 SPI设备节点属性
- 三、SPI设备树处理过程
- 四、总结
参考资料:
- 内核头文件:
include\linux\spi\spi.h - 内核文档:
Documentation\devicetree\bindings\spi\spi-bus.txt - 内核源码:
drivers\spi\spi.c - 内核源码:
drivers\spi\spi-gpio.c
一、SPI设备树节点构成

根据SPI的硬件连接框图,我们知道,当SPI控制器作为主设备时,SPI控制器下面可以挂接多个从设备。对应,设备树中就用一个SPI控制器节点作为父节点,在其下面包含子节点来表示从设备。设备树构成如下:
//根节点
/{//spi控制器节点xxx_spi{...//子节点1flash{...};//子节点2oled {...};};
}
二、SPI设备树示例
参考Documentation\devicetree\bindings\spi\spi-bus.txt示例:
spi@f00 {#address-cells = <1>;#size-cells = <0>;compatible = "fsl,mpc5200b-spi","fsl,mpc5200-spi";reg = <0xf00 0x20>;interrupts = <2 13 0 2 14 0>;cs-gpios = <&gpio1 20 0>, <&gpio1 21 0>;//子节点ethernet-switch@0 {compatible = "micrel,ks8995m";spi-max-frequency = <1000000>;reg = <0>;};//子节点codec@1 {compatible = "ti,tlv320aic26";spi-max-frequency = <100000>;reg = <1>;};};
2.1 SPI控制器节点属性
必须的属性:
#address-cells:这个SPI Master下的SPI设备,需要多少个cell来表述它的片选引脚,1就表示用一个32位数据来表示。#size-cells:必须设置为0。compatible:和SPI Master驱动进行比较配备。
可选的属性:
reg: 表示SPI Master 的寄存器地址和大小。interrupts: 描述中断。cs-gpios:SPI Master可以使用多个GPIO引脚当做片选,可以在这个属性列出那些GPIO引脚。- num-cs:片选引脚总数。
注:还有一些其他和驱动程序相关的属性,不同的SPI Master驱动程序要求的属性可能不一样。
2.2 SPI设备节点属性
必须的属性:
compatible:和SPI Device驱动进行比较匹配。reg:用来表示它使用哪个片选引脚。spi-max-frequency:该SPI设备支持的最大SPI时钟频率。
可选的属性:
spi-cpol:这是一个空属性(没有值),设置时钟起始电平,如果设置了表示值为1(高电平),没设置则默认0(低电平)。spi-cpha:这是一个空属性(没有值),设置第几个时钟沿采集数据。spi-cs-high:这是一个空属性(没有值),表示片选引脚高电平有效。spi-3wire:这是一个空属性(没有值),表示使用SPI 三线模式。spi-lsb-first:这是一个空属性(没有值),表示使用SPI传输数据时先传输最低位(LSB)。spi-tx-bus-width:表示有几条MOSI引脚;没有这个属性时默认只有1条MOSI引脚。spi-rx-bus-width:表示有几条MISO引脚;没有这个属性时默认只有1条MISO引脚。spi-rx-delay-us:单位是毫秒,表示每次读传输后要延时多久。spi-tx-delay-us:单位是毫秒,表示每次写传输后要延时多久。
三、SPI设备树处理过程
对于SPI控制器节点,会对应有一个SPI控制器驱动程序,SPI控制器驱动程序会解析父节点,构造出一个spi_master结构体并注册它,另外还会解析子节点,每个子节点会生成一个spi_device结构体。因此,整个SPI设备树节点,都是由SPI控制器驱动程序来解析的 。下面以GPIO模拟的SPI控制器:spi-gpio为例,看代码处理过程:
spi-gpio 设备树:
spi-gpio {compatible = "spi-gpio";#address-cells = <0x1>;gpio-sck = <&gpio 95 0>;gpio-miso = <&gpio 98 0>;gpio-mosi = <&gpio 97 0>;cs-gpios = <&gpio 125 0>;num-chipselects = <1>;/* clients */ };codec@1 {compatible = "ti,tlv320aic26";spi-max-frequency = <100000>;reg = <1>;};
驱动程序 spi-gpio.c:
- 从入口函数进入,这里的入口函数在这个宏
module_platform_driver里面。入口函数里面注册了一个platform_driver结构体。
//这是一个宏
module_platform_driver(spi_gpio_driver);
//宏展开后
static int __init spi_gpio_driver_init(void)
{return platform_driver_register(&spi_gpio_driver);
}
module_init(spi_gpio_driver_init);
static void __exit xxx_init(void)
{return platform_driver_unregister(&spi_gpio_driver);
}
module_exit(spi_gpio_driver_exit);
platform_driver和设备树匹配成功之后调用probe函数。
//platform_driver结构
static struct platform_driver spi_gpio_driver = {.driver = {.name = DRIVER_NAME,.of_match_table = of_match_ptr(spi_gpio_dt_ids),},.probe = spi_gpio_probe, //和设备树匹配成功后调用.remove = spi_gpio_remove,
};
//of_match_table
static const struct of_device_id spi_gpio_dt_ids[] = {{ .compatible = "spi-gpio" }, //和设备树进行比较{}
};
probe函数会分配、设置、注册一个spi_master
static int spi_gpio_probe(struct platform_device *pdev)
{...//分配spi_mastermaster = spi_alloc_master(&pdev->dev, sizeof(*spi_gpio) +(sizeof(unsigned long) * num_devices));...//设置spi_mastermaster->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32);master->flags = master_flags;master->bus_num = pdev->id;master->num_chipselect = num_devices;master->setup = spi_gpio_setup;master->cleanup = spi_gpio_cleanup;...//调用这个函数,里面会注册spi_masterstatus = spi_bitbang_start(&spi_gpio->bitbang);...
}
spi_bitbang_start函数里面注册spi_master
int spi_bitbang_start(struct spi_bitbang *bitbang)
{...//注册spi_masterret = spi_register_master(spi_master_get(master));...
}
spi_register_master里面调用of_spi_register_master解析设备树,并调用of_register_spi_devices注册spi_device。
int spi_register_master(struct spi_master *master)
{...//解析设备树status = of_spi_register_master(master);...//注册spi_deviceof_register_spi_devices(master);
}
of_register_spi_devices是复数,它里面会遍历调用of_register_spi_device注册spi_device。
tatic void of_register_spi_devices(struct spi_master *master)
{
...//遍历注册每一个子节点for_each_available_child_of_node(master->dev.of_node, nc) {
...//注册单个spi_devicespi = of_register_spi_device(master, nc);
...}}
}
of_register_spi_device里面解析子节点并调用spi_add_device添加spi_device。
static struct spi_device *
of_register_spi_device(struct spi_master *master, struct device_node *nc)
{struct spi_device *spi;int rc;u32 value;/* Alloc an spi_device */spi = spi_alloc_device(master); //分配spi_deviceif (!spi) {dev_err(&master->dev, "spi_device alloc error for %s\n",nc->full_name);rc = -ENOMEM;goto err_out;}/* Select device driver */rc = of_modalias_node(nc, spi->modalias,sizeof(spi->modalias));if (rc < 0) {dev_err(&master->dev, "cannot find modalias for %s\n",nc->full_name);goto err_out;}/* Device address */rc = of_property_read_u32(nc, "reg", &value); //取出reg属性if (rc) {dev_err(&master->dev, "%s has no valid 'reg' property (%d)\n",nc->full_name, rc);goto err_out;}spi->chip_select = value; //chip_select值来之reg属性/* Mode (clock phase/polarity/etc.) */ //模式设置if (of_find_property(nc, "spi-cpha", NULL))spi->mode |= SPI_CPHA;if (of_find_property(nc, "spi-cpol", NULL))spi->mode |= SPI_CPOL;if (of_find_property(nc, "spi-cs-high", NULL))spi->mode |= SPI_CS_HIGH;if (of_find_property(nc, "spi-3wire", NULL))spi->mode |= SPI_3WIRE;if (of_find_property(nc, "spi-lsb-first", NULL))spi->mode |= SPI_LSB_FIRST;/* Device DUAL/QUAD mode */if (!of_property_read_u32(nc, "spi-tx-bus-width", &value)) {switch (value) {case 1:break;case 2:spi->mode |= SPI_TX_DUAL;break;case 4:spi->mode |= SPI_TX_QUAD;break;default:dev_warn(&master->dev,"spi-tx-bus-width %d not supported\n",value);break;}}if (!of_property_read_u32(nc, "spi-rx-bus-width", &value)) {switch (value) {case 1:break;case 2:spi->mode |= SPI_RX_DUAL;break;case 4:spi->mode |= SPI_RX_QUAD;break;default:dev_warn(&master->dev,"spi-rx-bus-width %d not supported\n",value);break;}}/* Device speed */ //最大频率rc = of_property_read_u32(nc, "spi-max-frequency", &value);if (rc) {dev_err(&master->dev, "%s has no valid 'spi-max-frequency' property (%d)\n",nc->full_name, rc);goto err_out;}spi->max_speed_hz = value;/* Store a pointer to the node in the device structure */of_node_get(nc);spi->dev.of_node = nc;/* Register the new device */ //注册spi_devicerc = spi_add_device(spi);if (rc) {dev_err(&master->dev, "spi_device register error %s\n",nc->full_name);goto err_of_node_put;}return spi;err_of_node_put:of_node_put(nc);
err_out:spi_dev_put(spi);return ERR_PTR(rc);
}
四、总结
本文介绍分析了SPI设备树及其处理过程。
相关文章:
SPI驱动(三) -- SPI设备树处理过程
文章目录 参考资料:一、SPI设备树节点构成二、SPI设备树示例2.1 SPI控制器节点属性2.2 SPI设备节点属性 三、SPI设备树处理过程四、总结 参考资料: 内核头文件:include\linux\spi\spi.h内核文档:Documentation\devicetree\bindin…...
【RAG 篇】万字长文:向量数据库选型指南 —— Milvus 与 FAISS/Pinecone/Weaviate 等工具深度对比
大家好,我是大 F,深耕AI算法十余年,互联网大厂技术岗。分享AI算法干货、技术心得。 欢迎关注《大模型理论和实战》、《DeepSeek技术解析和实战》,一起探索技术的无限可能! 文章目录 向量数据库的核心价值主流工具横向对比 FAISS:Meta 的高效检索引擎Pinecone:全托管商业…...
机器学习数学基础:40.结构方程模型(SEM)中卡方值与卡方自由度比
结构方程模型(SEM)中卡方值与卡方自由度比教程 在结构方程模型分析里,卡方值和卡方自由度比是评估模型拟合程度的重要指标,下面为大家详细介绍。 一、卡方值(CMIN) (一)基本概念与…...
MARL零样本协调之Fictitious Co-Play学习笔记
下列引用来自知乎作者Algernon 知乎link FCP作为ZSC领域两阶段训练方法的开创者 论文《Collaborating with Humans without Human Data》来自 NeurIPS 2021。这篇论文提出 Fictitious Co-Play (FCP) 来解决 ZSC 问题。论文认为,ZSC 的第一个重要问题是对称性&#x…...
idea中的查看git历史记录,不显示详细信息
一、正常情况显示 1、idea中git查看history正常显示如下图: 二、非正常情况下显示 1、idea中git查看history,现在不显示提交的历史文件详细信息,如下图: 三、解决方式 1、找到如下窗口中画红色框的黑色线条,鼠标放在…...
Redis——快速入门
目录 Redis简介 安装配置(Windows) GUI工具RedisInsight的使用 十大数据类型(5基本5高级) 字符串String 列表List 集合Set(S) 有序集合SortedSet(Z) 哈希Hash(H) 发布订阅模式 消息队列Stream(X) 地理空间Geospatial(GEO) HyperLogLog(PF) …...
LLM 模型 Prompt 工程
目录 1、Prompt 基础概念 2、Prompt 主要构成 3、Prompt 相关技术 3.1、思维链 3.2、自洽性 3.3、思维树 1、Prompt 基础概念 Prompt 工程是通过设计和优化自然语言提示(Prompt),引导LLM生成符合特定任务需求的输出的技术。其核心目标是…...
10个实用IntelliJ IDEA插件
精心整理了最新的面试资料和简历模板,有需要的可以自行获取 点击前往百度网盘获取 点击前往夸克网盘获取 以下是为提升开发效率推荐的10个实用IntelliJ IDEA插件,涵盖代码质量、效率工具及热门框架支持: 一、代码质量与规范 SonarLint 实时…...
Vue中实现大文件的切片并发下载和下载进度展示
Vue中实现大文件的切片下载 切片下载需要后端提供两个接口,第一个接口用来获取当前下载文件的总切片数,第二个接口用来获取具体某一个切片的内容。 界面展示 数据流展示 代码 接口 // 切片下载-获取文件的总切片数 export function getChunkDownload…...
开源表单、投票、测评平台部署教程
填鸭表单联合宝塔面板深度定制,自宝塔面板 9.2 版本开始,在宝塔面板-软件商店中可以一键部署填鸭表单系统。 简单操作即可拥有属于自己的表单问卷系统,快速赋能业务。即使小白用户也能轻松上手。 社区版体验地址:https://demo.tduckapp.com/home 前端项目地址: tduck-fro…...
GaussDB性能调优技术指南
一、性能调优核心目标 降低响应时间:缩短单次查询或事务的处理时间(如从秒级优化到毫秒级)。 提高吞吐量:支撑更高并发请求(如从千次/秒提升到百万次/秒)。 资源高效利用:减少 CPU、…...
【后端开发】go-zero微服务框架实践(goland框架对比,go-zero开发实践,文件上传问题优化等等)
【后端开发】go-zero微服务框架实践(goland框架对比,go-zero开发实践,文件上传问题优化等) 文章目录 1、go框架对比介绍2、go-zero 微服务开发实践3、go-zero 文件上传问题优化 1、go框架对比介绍 国内开源goland框架对比 1 go-…...
C#—csv文件格式操作实例【在winform表格中操作csv】
C#—csv文件格式操作实例【在winform表格中操作csv】 实例一 实例效果 当在winform界面中点击读取按钮时 将csv中的所有数据读取出来放置在datagridview控件,可以在datagridview控件中编辑数据,当点击保存按钮时 将datagridview控件中的所有数据存储在…...
一周学会Flask3 Python Web开发-WTForms表单验证
锋哥原创的Flask3 Python Web开发 Flask3视频教程: 2025版 Flask3 Python web开发 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili 我们可以通过WTForms表单类属性的validators属性来实现表单验证。 常用的WTForms验证器 验证器说明DataRequired(messageNo…...
23种设计模式一览【设计模式】
文章目录 前言一、创建型模式(Creational Patterns)二、结构型模式(Structural Patterns)三、行为型模式(Behavioral Patterns) 前言 设计模式是软件工程中用来解决特定问题的一组解决方案。它们是经过验证…...
GPIO及其应用
GPIO及其应用 文章目录 GPIO及其应用1.GPIO概括2.GPIO工作基本结构3.GPIO寄存器3.1寄存器总览3.2寄存器功能3.3BIT简写的代表 4.GPIO的电气特性4.1拉电流与灌电流4.2驱动大功率负载4.3电平逻辑兼容性 5.LED闪烁(实操)6.LED交替闪烁(实操)7.开关控制LED灯…...
NO1.C++语言基础|四种智能指针|内存分配情况|指针传擦和引用传参|const和static|c和c++的区别
1. 说⼀下你理解的 C 中的四种智能指针 智能指针的作用是管理指针,可以避免内存泄漏的发生。 智能指针就是一个类,当超出了类的作用域时,就会调用析构函数,这时就会自动释放资源。 所以智能指针作用的原理就是在函数结束时自动释…...
Vue 关于如何在vue中实现跨域请求问题
📚首先,让我们了解一下什么是跨域。当一个请求的URL的协议、域名、端口三者中任意一个与当前页面的URL不同,就称为跨域请求。 🔒为什么会出现跨域问题呢?这是因为浏览器的同源策略限制。同源策略是浏览器最核心的安全…...
毕业项目推荐:基于yolov8/yolov5/yolo11的暴力行为检测识别系统(python+卷积神经网络)
文章目录 概要一、整体资源介绍技术要点功能展示:功能1 支持单张图片识别功能2 支持遍历文件夹识别功能3 支持识别视频文件功能4 支持摄像头识别功能5 支持结果文件导出(xls格式)功能6 支持切换检测到的目标查看 二、数据集三、算法介绍1. YO…...
算法随笔_64: 含特定字母的最小子序列
上一篇:算法随笔_63: 子数组范围和-CSDN博客 题目描述如下: 给你一个字符串 s ,一个整数 k ,一个字母 letter 以及另一个整数 repetition 。 返回 s 中长度为 k 且 字典序最小 的子序列,该子序列同时应满足字母 letter 出现 至少 repetitio…...
red hat系统离线部署Deepseek
一个人在单位离线部署踩了不少坑,记录一下 模型准备 1.huggingface下载gguf文件,将文件放到相应目录(例如E:/AI文件夹) 2.在文件夹内用文本建一个文件,命名Modelfile(删除txt后缀) 3.用文本编辑器打开Modelfile,在文本内输入 fr…...
torch.einsum 的 10 个常见用法详解以及多头注意力实现
torch.einsum 是 PyTorch 提供的一个高效的张量运算函数,能够用紧凑的 Einstein Summation 约定(Einstein Summation Convention, Einsum)描述复杂的张量操作,例如矩阵乘法、转置、内积、外积、批量矩阵乘法等。 1. 基本语法 tor…...
【DeepSeek】一文详解GRPO算法——为什么能减少大模型训练资源?
GRPO,一种新的强化学习方法,是DeepSeek R1使用到的训练方法。 今天的这篇博客文章,笔者会从零开始,层层递进地为各位介绍一种在强化学习中极具实用价值的技术——GRPO(Group Relative Policy Optimization)…...
C++基础系列【19】运算符重载
博主介绍:程序喵大人 35- 资深C/C/Rust/Android/iOS客户端开发10年大厂工作经验嵌入式/人工智能/自动驾驶/音视频/游戏开发入门级选手《C20高级编程》《C23高级编程》等多本书籍著译者更多原创精品文章,首发gzh,见文末👇…...
大数据环境(单机版) Flume传输数据到Kafka
文章目录 前言一、准备二、安装三、配置环境变量四、修改配置4.1、kafka配置4.2、Flume配置 五、启动程序5.1、启动zk5.2、启动kafka5.3、启动flume 六、测试6.1、启动一个kafka终端,用来消费消息6.2、写入日志 其他 前言 flume监控指定目录,传输数据到…...
Ollama 框架本地部署教程:开源定制,为AI 项目打造专属解决方案!
Ollama 是一款开源的本地大语言模型(LLM)运行框架,用于管理和运行语言模型。具有以下核心特点: 开源可定制:采用 MIT 开源协议,开发者能自由使用、阅读源码并定制,可根据自身需求进行功能扩展和…...
开发环境搭建-03.后端环境搭建-使用Git进行版本控制
一.Git进行版本控制 我们对项目开发就会产生很多代码,我们需要有效的将这些代码管理起来,因此我们真正开发代码前需要把我们的Git环境搭建好。通过Git来管理我们项目的版本,进而实现版本控制。 首先我们使用Git创建本地仓库,然后…...
[Lc(2)滑动窗口_1] 长度最小的数组 | 无重复字符的最长子串 | 最大连续1的个数 III | 将 x 减到 0 的最小操作数
目录 1. 长度最小的字数组 题解 代码 ⭕2.无重复字符的最长子串 题解 代码 3.最大连续1的个数 III 题解 代码 4.将 x 减到 0 的最小操作数 题解 代码 1. 长度最小的字数组 题目链接:209.长度最小的字数组 题目分析: 给定一个含有 n 个 正整数 的数组…...
互联网时代如何保证数字足迹的安全,以防个人信息泄露?
用户在网络上所做的几乎所有事情,包括浏览、社交媒体活动、搜索查询、在线订阅,甚至购物,都会留下一条数据线索,这些数据可用于创建用户在线身份的详细档案。如果这些信息暴露,恶意行为者可能会利用它们将用户置于各种…...
海康摄像头接入流媒体服务器实现https域名代理播放
环境 操作系统:Ubuntu 22.04流媒体服务器:srs 官网安装教程srs开启GB28181协议 官网开启教程进行海康摄像头的配置 官网配置教程srs使用systemctl实现开机自启 官网配置教程 nginx配置说明 server {listen 80;server_name a.com;return 301 https://$…...
