当前位置: 首页 > article >正文

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设备树处理过程

文章目录 参考资料&#xff1a;一、SPI设备树节点构成二、SPI设备树示例2.1 SPI控制器节点属性2.2 SPI设备节点属性 三、SPI设备树处理过程四、总结 参考资料&#xff1a; 内核头文件&#xff1a;include\linux\spi\spi.h内核文档&#xff1a;Documentation\devicetree\bindin…...

【RAG 篇】万字长文:向量数据库选型指南 —— Milvus 与 FAISS/Pinecone/Weaviate 等工具深度对比

大家好,我是大 F,深耕AI算法十余年,互联网大厂技术岗。分享AI算法干货、技术心得。 欢迎关注《大模型理论和实战》、《DeepSeek技术解析和实战》,一起探索技术的无限可能! 文章目录 向量数据库的核心价值主流工具横向对比 FAISS:Meta 的高效检索引擎Pinecone:全托管商业…...

机器学习数学基础:40.结构方程模型(SEM)中卡方值与卡方自由度比

结构方程模型&#xff08;SEM&#xff09;中卡方值与卡方自由度比教程 在结构方程模型分析里&#xff0c;卡方值和卡方自由度比是评估模型拟合程度的重要指标&#xff0c;下面为大家详细介绍。 一、卡方值&#xff08;CMIN&#xff09; &#xff08;一&#xff09;基本概念与…...

MARL零样本协调之Fictitious Co-Play学习笔记

下列引用来自知乎作者Algernon 知乎link FCP作为ZSC领域两阶段训练方法的开创者 论文《Collaborating with Humans without Human Data》来自 NeurIPS 2021。这篇论文提出 Fictitious Co-Play (FCP) 来解决 ZSC 问题。论文认为&#xff0c;ZSC 的第一个重要问题是对称性&#x…...

idea中的查看git历史记录,不显示详细信息

一、正常情况显示 1、idea中git查看history正常显示如下图&#xff1a; 二、非正常情况下显示 1、idea中git查看history&#xff0c;现在不显示提交的历史文件详细信息&#xff0c;如下图&#xff1a; 三、解决方式 1、找到如下窗口中画红色框的黑色线条&#xff0c;鼠标放在…...

Redis——快速入门

目录 Redis简介 安装配置(Windows) GUI工具RedisInsight的使用 十大数据类型&#xff08;5基本5高级&#xff09; 字符串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 工程是通过设计和优化自然语言提示&#xff08;Prompt&#xff09;&#xff0c;引导LLM生成符合特定任务需求的输出的技术。其核心目标是…...

10个实用IntelliJ IDEA插件

精心整理了最新的面试资料和简历模板&#xff0c;有需要的可以自行获取 点击前往百度网盘获取 点击前往夸克网盘获取 以下是为提升开发效率推荐的10个实用IntelliJ IDEA插件&#xff0c;涵盖代码质量、效率工具及热门框架支持&#xff1a; 一、代码质量与规范 SonarLint 实时…...

Vue中实现大文件的切片并发下载和下载进度展示

Vue中实现大文件的切片下载 切片下载需要后端提供两个接口&#xff0c;第一个接口用来获取当前下载文件的总切片数&#xff0c;第二个接口用来获取具体某一个切片的内容。 界面展示 数据流展示 代码 接口 // 切片下载-获取文件的总切片数 export function getChunkDownload…...

开源表单、投票、测评平台部署教程

填鸭表单联合宝塔面板深度定制,自宝塔面板 9.2 版本开始,在宝塔面板-软件商店中可以一键部署填鸭表单系统。 简单操作即可拥有属于自己的表单问卷系统,快速赋能业务。即使小白用户也能轻松上手。 社区版体验地址:https://demo.tduckapp.com/home 前端项目地址: tduck-fro…...

GaussDB性能调优技术指南

​一、性能调优核心目标 ​降低响应时间&#xff1a;缩短单次查询或事务的处理时间&#xff08;如从秒级优化到毫秒级&#xff09;。 ​提高吞吐量&#xff1a;支撑更高并发请求&#xff08;如从千次/秒提升到百万次/秒&#xff09;。 ​资源高效利用&#xff1a;减少 CPU、…...

【后端开发】go-zero微服务框架实践(goland框架对比,go-zero开发实践,文件上传问题优化等等)

【后端开发】go-zero微服务框架实践&#xff08;goland框架对比&#xff0c;go-zero开发实践&#xff0c;文件上传问题优化等&#xff09; 文章目录 1、go框架对比介绍2、go-zero 微服务开发实践3、go-zero 文件上传问题优化 1、go框架对比介绍 国内开源goland框架对比 1 go-…...

C#—csv文件格式操作实例【在winform表格中操作csv】

C#—csv文件格式操作实例【在winform表格中操作csv】 实例一 实例效果 当在winform界面中点击读取按钮时 将csv中的所有数据读取出来放置在datagridview控件&#xff0c;可以在datagridview控件中编辑数据&#xff0c;当点击保存按钮时 将datagridview控件中的所有数据存储在…...

一周学会Flask3 Python Web开发-WTForms表单验证

锋哥原创的Flask3 Python Web开发 Flask3视频教程&#xff1a; 2025版 Flask3 Python web开发 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili 我们可以通过WTForms表单类属性的validators属性来实现表单验证。 常用的WTForms验证器 验证器说明DataRequired(messageNo…...

23种设计模式一览【设计模式】

文章目录 前言一、创建型模式&#xff08;Creational Patterns&#xff09;二、结构型模式&#xff08;Structural Patterns&#xff09;三、行为型模式&#xff08;Behavioral Patterns&#xff09; 前言 设计模式是软件工程中用来解决特定问题的一组解决方案。它们是经过验证…...

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交替闪烁&#xff08;实操&#xff09;7.开关控制LED灯…...

NO1.C++语言基础|四种智能指针|内存分配情况|指针传擦和引用传参|const和static|c和c++的区别

1. 说⼀下你理解的 C 中的四种智能指针 智能指针的作用是管理指针&#xff0c;可以避免内存泄漏的发生。 智能指针就是一个类&#xff0c;当超出了类的作用域时&#xff0c;就会调用析构函数&#xff0c;这时就会自动释放资源。 所以智能指针作用的原理就是在函数结束时自动释…...

Vue 关于如何在vue中实现跨域请求问题

&#x1f4da;首先&#xff0c;让我们了解一下什么是跨域。当一个请求的URL的协议、域名、端口三者中任意一个与当前页面的URL不同&#xff0c;就称为跨域请求。 &#x1f512;为什么会出现跨域问题呢&#xff1f;这是因为浏览器的同源策略限制。同源策略是浏览器最核心的安全…...

毕业项目推荐:基于yolov8/yolov5/yolo11的暴力行为检测识别系统(python+卷积神经网络)

文章目录 概要一、整体资源介绍技术要点功能展示&#xff1a;功能1 支持单张图片识别功能2 支持遍历文件夹识别功能3 支持识别视频文件功能4 支持摄像头识别功能5 支持结果文件导出&#xff08;xls格式&#xff09;功能6 支持切换检测到的目标查看 二、数据集三、算法介绍1. YO…...

算法随笔_64: 含特定字母的最小子序列

上一篇:算法随笔_63: 子数组范围和-CSDN博客 题目描述如下: 给你一个字符串 s &#xff0c;一个整数 k &#xff0c;一个字母 letter 以及另一个整数 repetition 。 返回 s 中长度为 k 且 字典序最小 的子序列&#xff0c;该子序列同时应满足字母 letter 出现 至少 repetitio…...

red hat系统离线部署Deepseek

一个人在单位离线部署踩了不少坑&#xff0c;记录一下 模型准备 1.huggingface下载gguf文件&#xff0c;将文件放到相应目录(例如E:/AI文件夹) 2.在文件夹内用文本建一个文件&#xff0c;命名Modelfile(删除txt后缀) 3.用文本编辑器打开Modelfile&#xff0c;在文本内输入 fr…...

torch.einsum 的 10 个常见用法详解以及多头注意力实现

torch.einsum 是 PyTorch 提供的一个高效的张量运算函数&#xff0c;能够用紧凑的 Einstein Summation 约定&#xff08;Einstein Summation Convention, Einsum&#xff09;描述复杂的张量操作&#xff0c;例如矩阵乘法、转置、内积、外积、批量矩阵乘法等。 1. 基本语法 tor…...

【DeepSeek】一文详解GRPO算法——为什么能减少大模型训练资源?

GRPO&#xff0c;一种新的强化学习方法&#xff0c;是DeepSeek R1使用到的训练方法。 今天的这篇博客文章&#xff0c;笔者会从零开始&#xff0c;层层递进地为各位介绍一种在强化学习中极具实用价值的技术——GRPO&#xff08;Group Relative Policy Optimization&#xff09…...

C++基础系列【19】运算符重载

博主介绍&#xff1a;程序喵大人 35- 资深C/C/Rust/Android/iOS客户端开发10年大厂工作经验嵌入式/人工智能/自动驾驶/音视频/游戏开发入门级选手《C20高级编程》《C23高级编程》等多本书籍著译者更多原创精品文章&#xff0c;首发gzh&#xff0c;见文末&#x1f447;&#x1f…...

大数据环境(单机版) Flume传输数据到Kafka

文章目录 前言一、准备二、安装三、配置环境变量四、修改配置4.1、kafka配置4.2、Flume配置 五、启动程序5.1、启动zk5.2、启动kafka5.3、启动flume 六、测试6.1、启动一个kafka终端&#xff0c;用来消费消息6.2、写入日志 其他 前言 flume监控指定目录&#xff0c;传输数据到…...

Ollama 框架本地部署教程:开源定制,为AI 项目打造专属解决方案!

Ollama 是一款开源的本地大语言模型&#xff08;LLM&#xff09;运行框架&#xff0c;用于管理和运行语言模型。具有以下核心特点&#xff1a; 开源可定制&#xff1a;采用 MIT 开源协议&#xff0c;开发者能自由使用、阅读源码并定制&#xff0c;可根据自身需求进行功能扩展和…...

开发环境搭建-03.后端环境搭建-使用Git进行版本控制

一.Git进行版本控制 我们对项目开发就会产生很多代码&#xff0c;我们需要有效的将这些代码管理起来&#xff0c;因此我们真正开发代码前需要把我们的Git环境搭建好。通过Git来管理我们项目的版本&#xff0c;进而实现版本控制。 首先我们使用Git创建本地仓库&#xff0c;然后…...

[Lc(2)滑动窗口_1] 长度最小的数组 | 无重复字符的最长子串 | 最大连续1的个数 III | 将 x 减到 0 的最小操作数

目录 1. 长度最小的字数组 题解 代码 ⭕2.无重复字符的最长子串 题解 代码 3.最大连续1的个数 III 题解 代码 4.将 x 减到 0 的最小操作数 题解 代码 1. 长度最小的字数组 题目链接&#xff1a;209.长度最小的字数组 题目分析: 给定一个含有 n 个 正整数 的数组…...

互联网时代如何保证数字足迹的安全,以防个人信息泄露?

用户在网络上所做的几乎所有事情&#xff0c;包括浏览、社交媒体活动、搜索查询、在线订阅&#xff0c;甚至购物&#xff0c;都会留下一条数据线索&#xff0c;这些数据可用于创建用户在线身份的详细档案。如果这些信息暴露&#xff0c;恶意行为者可能会利用它们将用户置于各种…...

海康摄像头接入流媒体服务器实现https域名代理播放

环境 操作系统&#xff1a;Ubuntu 22.04流媒体服务器&#xff1a;srs 官网安装教程srs开启GB28181协议 官网开启教程进行海康摄像头的配置 官网配置教程srs使用systemctl实现开机自启 官网配置教程 nginx配置说明 server {listen 80;server_name a.com;return 301 https://$…...