RK3568驱动指南|第十一篇 pinctrl 子系统-第127章 猜想验证

瑞芯微RK3568芯片是一款定位中高端的通用型SOC,采用22nm制程工艺,搭载一颗四核Cortex-A55处理器和Mali G52 2EE 图形处理器。RK3568 支持4K 解码和 1080P 编码,支持SATA/PCIE/USB3.0 外围接口。RK3568内置独立NPU,可用于轻量级人工智能应用。RK3568 支持安卓 11 和 linux 系统,主要面向物联网网关、NVR 存储、工控平板、工业检测、工控盒、卡拉 OK、云终端、车载中控等行业。


【公众号】迅为电子

【粉丝群】824412014(加群获取驱动文档+例程)

【视频观看】嵌入式学习之Linux驱动(第十一篇 pinctrl 子系统_全新升级)_基于RK3568

【购买链接】迅为RK3568开发板瑞芯微Linux安卓鸿蒙ARM核心板人工智能AI主板


第127章 猜想验证

经过了前面章节的学习,我们已经对pinctrl子系统中有了一定的了解,下面就来解决我们在120.2小节中提出的问题。

首先对问题进行一下复述,假如我们要配置一个LED外设,该LED需要使用一个管脚来进行亮灭的控制,那这个控制引脚需要复用成GPIO之后才能完成相应的功能,那pinctrl子系统是什么时候对该引脚进行的复用呢?

首先我们可以提出两种猜想,第一个猜想是在加载LED驱动的时候进行的pinctrl引脚复用,第二种猜想是在加载pinctrl驱动的时候完成的引脚复用。下面对这两种猜想进行验证。

1.猜想1验证

第一个猜想是在加载LED驱动的时候进行的pinctrl引脚复用,这就符合我们124章、125章、126章所讲解的内容。当LED灯的设备树和驱动匹配之后,就会进入驱动中编写的probe函数,在此之前会执行“drivers/base/dd.c”文件中的really probe函数中的子函数pinctrl_bind_pins,该函数会为给定的设备绑定引脚,并在绑定过程中选择和设置适当的pinctrl状态。具体的绑定细节可以去前面的章节中查找。

2.猜想2验证

第二种猜想是在加载pinctrl驱动的时候完成的引脚复用,因为pinctrl子系统也是符合设备模型的规范,也会执行相应的probe函数,所以同样的加在pinctrl驱动时也会执行“drivers/base/dd.c”文件中的really probe函数中的子函数pinctrl_bind_pins,那这时会进行pinctrl管脚的复用设置吗,接下来我们对此进行深入的分析。

在pinctrl的probe函数执行之前,会调用pinctrl_bind_pins函数,根据124.2小节中讲解到的内容可以知道,根据函数的嵌套,首先会调用的create_pinctrl函数创建struct pinctrl 类型的引脚控制器,create_pinctrl函数内容如下所示:

static struct pinctrl *create_pinctrl(struct device *dev,struct pinctrl_dev *pctldev)
{struct pinctrl *p;const char *devname;struct pinctrl_maps *maps_node;int i;const struct pinctrl_map *map;int ret;/** 为每个映射创建状态 cookie 持有者 struct pinctrl。* 这是当使用 pinctrl_get() 请求引脚控制句柄时消费者将获得的对象。*/p = kzalloc(sizeof(*p), GFP_KERNEL);if (!p)return ERR_PTR(-ENOMEM);p->dev = dev;INIT_LIST_HEAD(&p->states);INIT_LIST_HEAD(&p->dt_maps);ret = pinctrl_dt_to_map(p, pctldev);if (ret < 0) {kfree(p);return ERR_PTR(ret);}devname = dev_name(dev);mutex_lock(&pinctrl_maps_mutex);/* 遍历引脚控制映射以定位正确的映射 */for_each_maps(maps_node, i, map) {/* 映射必须适用于此设备 */if (strcmp(map->dev_name, devname))continue;/** 如果 pctldev 不为空,我们正在声明它的独占使用权,* 这意味着它自己提供了该设置。** 因此,我们必须跳过适用于此设备但由其他设备提供的映射。*/if (pctldev &&strcmp(dev_name(pctldev->dev), map->ctrl_dev_name))continue;ret = add_setting(p, pctldev, map);/** 在这一点上,添加设置可能会导致:** - 延迟,如果引脚控制设备尚不可用* - 失败,如果引脚控制设备尚不可用,*   并且该设置是一个独占设置。我们不能推迟它,因为*   该独占设置会在设备注册后立即生效。** 如果返回的错误不是 -EPROBE_DEFER,则我们将* 累积错误,以查看是否最终得到 -EPROBE_DEFER,* 因为那是最糟糕的情况。*/if (ret == -EPROBE_DEFER) {pinctrl_free(p, false);mutex_unlock(&pinctrl_maps_mutex);return ERR_PTR(ret);}}mutex_unlock(&pinctrl_maps_mutex);if (ret < 0) {/* 如果发生了除推迟以外的其他错误,则在此处返回 */pinctrl_free(p, false);return ERR_PTR(ret);}kref_init(&p->users);/* 将引脚控制句柄添加到全局列表 */mutex_lock(&pinctrl_list_mutex);list_add_tail(&p->node, &pinctrl_list);mutex_unlock(&pinctrl_list_mutex);return p;
}

在第22行会调用 pinctrl_dt_to_map 函数将设备树中定义的引脚映射信息转换为 struct pinctrl_map 结构,并将其添加到 p->dt_maps 链表中。该函数定义在内核源码目录下的“drivers/pinctrl/devicetree.c”文件中,具体内容如下所示:

int pinctrl_dt_to_map(struct pinctrl *p, struct pinctrl_dev *pctldev)
{struct device_node *np = p->dev->of_node;  // 获取引脚控制器关联设备的设备树节点int state, ret;char *propname;struct property *prop;const char *statename;const __be32 *list;int size, config;phandle phandle;struct device_node *np_config;/* 如果 CONFIG_OF 启用,且 p->dev 不是从设备树实例化而来 */if (!np) {if (of_have_populated_dt())dev_dbg(p->dev, "no of_node; not parsing pinctrl DT\n");return 0;}/* 节点内部存储属性名称的指针 */of_node_get(np);/* 对于每个定义的状态 ID */for (state = 0;; state++) {/* 获取 pinctrl-* 属性 */propname = kasprintf(GFP_KERNEL, "pinctrl-%d", state);prop = of_find_property(np, propname, &size);kfree(propname);if (!prop) {if (state == 0) {of_node_put(np);return -ENODEV;}break;}list = prop->value;size /= sizeof(*list);/* 判断 pinctrl-names 属性是否命名了该状态 */ret = of_property_read_string_index(np, "pinctrl-names", state, &statename);/** 如果未命名,则 statename 仅是整数状态 ID。但是,为了避免动态分配和之后要释放的麻烦,* 可以直接将 statename 指向属性名称的一部分。*/if (ret < 0) {/* strlen("pinctrl-") == 8 */statename = prop->name + 8;}/* 对于其中的每个引用的引脚配置节点 */for (config = 0; config < size; config++) {phandle = be32_to_cpup(list++);/* 查找引脚配置节点 */np_config = of_find_node_by_phandle(phandle);if (!np_config) {dev_err(p->dev, "prop %s index %i invalid phandle\n", prop->name, config);ret = -EINVAL;goto err;}/* 解析节点 */ret = dt_to_map_one_config(p, pctldev, statename, np_config);of_node_put(np_config);if (ret < 0)goto err;}/* 如果在设备树中没有条目,则生成一个虚拟状态表条目 */if (!size) {ret = dt_remember_dummy_state(p, statename);if (ret < 0)goto err;}}return 0;err:pinctrl_dt_free_maps(p);return ret;
}

这里传递过来的是pinctrl的设备树节点,在24-76行的for循环中会获取 pinctrl-* 属性,而在pinctrl节点中并没有该属性,pinctrl-* 属性是在一系列的设备节点中添加的,所以会在这里返回错误,同样的错误会一层层的向上级函数传递,最终导致pinctrl_bind_pins函数返回错误,从而不能设置引脚的复用,所以猜想2是不正确的。

在121章中也讲解了瑞芯微的pinctrl的probe函数,在该函数中有一个这样的调用关系:

rockchip pinctrl_proberockchip_pinctrl_registérdevm_pinctrl_registerpinctrl_registerpinctrl_enablepinctrl_claim_hogscreate_pinctrl

从上面的调用关系可以得到pinctrl的probe函数最后也会调用create_pinctrl来创建struct pinctrl 类型的引脚控制器,从而实现pinctrl引脚复用设置,同样的这是的设置也是不成功的,pinctrl_claim_hogs函数定义在内核源码目录下的“drivers/pinctrl/core.c”文件中,具体内容如下所示:

static int pinctrl_claim_hogs(struct pinctrl_dev *pctldev)
{pctldev->p = create_pinctrl(pctldev->dev, pctldev);if (PTR_ERR(pctldev->p) == -ENODEV) {dev_dbg(pctldev->dev, "no hogs found\n");return 0;}if (IS_ERR(pctldev->p)) {dev_err(pctldev->dev, "error claiming hogs: %li\n",PTR_ERR(pctldev->p));return PTR_ERR(pctldev->p);}pctldev->hog_default =pinctrl_lookup_state(pctldev->p, PINCTRL_STATE_DEFAULT);if (IS_ERR(pctldev->hog_default)) {dev_dbg(pctldev->dev,"failed to lookup the default state\n");} else {if (pinctrl_select_state(pctldev->p,pctldev->hog_default))dev_err(pctldev->dev,"failed to select default state\n");}pctldev->hog_sleep =pinctrl_lookup_state(pctldev->p,PINCTRL_STATE_SLEEP);if (IS_ERR(pctldev->hog_sleep))dev_dbg(pctldev->dev,"failed to lookup the sleep state\n");return 0;
}

该函数和pinctrl_bind_pins函数内容相似,所以也会在第二行的create_pinctrl函数返回错误,所以也就无法执行后面的pinctrl状态的选择和设置了,所以猜想2不成立。

至此,关于pinctrl的相关知识和疑问就都讲解和解答完成了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/616122.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

LocalDateTime与时间戳转换的全局配置

问题 在开发中&#xff0c;我们使用LocalDateTime为时间类型作为返回给前端&#xff0c;或者接收给前端的值&#xff0c;经常遇到返回变成了这种形式。 {"timestamp": [2024,1,12,16,36,29,592604100] }所以我们需要规定一种统一格式来进行接收与返回&#xff0c;我…

数据中心建设之——理解基于财务三大报表的BI指标体系搭建

目录 1.1 三张报表的作用 1.2 三张报表长的样子 1.2.1 资产负债表 1.2.2 利润表 1.2.3 现金流 1.3 BI指标构建 1.3.1 盈利能力指标构建 1.3.2 营运能力指标构建 1.3.3 偿债能力指标构建 转眼间&#xff0c;一年又悄然而逝&#xff0c;时光荏苒&#xff0c;岁月如梭 &a…

仓储|仓库管理水墨屏RFID电子标签2.4G基站CK-RTLS0501G功能说明与安装方式

随着全球智能制造进度的推进以及物流智能化管理水平的升级&#xff0c;行业亟需一种既能实现RFID批量读取、又能替代纸质标签在循环作业、供应链管理以及实现动态条码标签显示的产品。在此种行业需求背景下&#xff0c;我是适时推出了基于墨水屏显示技术的VT系列可视化超高频标…

JVM-JVM支持高并发底层原理精讲

一、透彻掌握高并发-从理解JVM开始 二、从线程的开闭看JVM的作用 1.run方法 启动start方法&#xff0c;会调用底层C方法&#xff0c;告诉操作系统当前线程处于可运行状态&#xff0c;而如果直接调用run方法&#xff0c;则就不是以线程的方式来运行了&#xff0c;只是当做一个普…

一套成熟的Spring Cloud智慧工地平台源码,自主版权,支持二次开发!

智慧工地源码&#xff0c;java语言开发的智慧工地源码 智慧工地利用移动互联、物联网、云计算、大数据等新一代信息技术&#xff0c;彻底改变传统施工现场各参建方的交互方式、工作方式和管理模式&#xff0c;为建设集团、施工企业、监理单位、设计单位、政府监管部门等提供一揽…

【Databend】基础函数应用

文章目录 数值函数字符串函数逻辑函数JSON 函数聚合函数总结 数值函数 使用频率较高的数值函数如下&#xff1a; abs(x)&#xff1a;参数x的绝对值。ceil(x)&#xff1a;参数x向上取整。floor(x)&#xff1a;参数x向下取整。rand([n])&#xff1a;生成 [0,1&#xff09;的浮点…

RabbitMQ(十)队列的声明方式

目录 1.编程式声明补充&#xff1a;RabbitTemplate 和 AmqpAdmin 的区别 2.声明式声明补充&#xff1a;new Queue() 和 QueueBuilder.durable(queueName).build() 的区别 背景&#xff1a; 在学习 RabbitMQ 的使用时&#xff0c; 经常会遇到不同的队列声明方式&#xff0c;有的…

酚醛胶面建筑模板 — 广西厂家直销,质保可靠

在现代建筑行业中&#xff0c;选择高质量的建筑板材对于确保施工质量和工程安全至关重要。广西厂家直销的酚醛胶面建筑板&#xff0c;以其卓越的质量和可靠的质保&#xff0c;成为了建筑行业的优选材料。 产品特性 卓越的耐候性&#xff1a;我们的酚醛胶面建筑板采用高品质酚醛…

图文看懂Android的Matrix原理

Matrix结构 在Android开发中&#xff0c;矩阵是一个非常强大且有趣的工具。位于图形库中&#xff0c;android.graphics.Matrix 是一个 33 的 float 矩阵&#xff0c;其主要作用是坐标变换。 它的结构大概是这样的&#xff1a; 其中每个位置的数值作用和其名称所代表的的含义是…

【写作】短篇《相遇与相守》

文章目录 前言背景角色故事梗概 第一章 缘分的邂逅第二章 心动的瞬间第三章 甜蜜的日子第四章 误会与和解第五章 共度风雨 前言 背景 时代背景 现代&#xff0c;一个充满忙碌和喧嚣的都市。这个都市是许多年轻人追求梦想和奋斗的地方&#xff0c;但也是许多人渴望寻找真挚感情…

Vue-18、Vue人员列表排序

<!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>列表排序</title><script type"text/javascript" src"https://cdn.jsdelivr.net/npm/vue2/dist/vue.js"></script…

Linux中DCHP与时间同步

目录 一、DHCP &#xff08;一&#xff09;工作原理 1.获取 2.续约 &#xff08;二&#xff09;分配方式 &#xff08;三&#xff09;服务器配置 1.随机地址分配 2.固定地址分配 二、时间同步 &#xff08;一&#xff09;ntpdate &#xff08;二&#xff09;chrony …

window-nginx注册服务(nginx-1.24.0.zip)

window-nginx注册服务(nginx-1.24.0.zip) 1、下载当前windows版nginx的稳定版本。 https://nginx.org/en/download.html 2、解压到指定目录中&#xff0c;这里解压到D盘根目录&#xff0c;D:\nginx-1.24.0 3、管理员打开命令行&#xff0c;可先进行相关操作&#xff0c;看一下n…

掌握Adams许可分析数据可视化技巧,轻松实现高效宣传

在这个信息爆炸的时代&#xff0c;数据可视化已经成为宣传和营销的重要工具。Adams许可分析数据可视化技巧以其独特的优势&#xff0c;帮助企业和个人更好地理解数据&#xff0c;呈现信息&#xff0c;吸引受众。本文将带您了解Adams许可分析数据可视化技巧&#xff0c;并探讨如…

create_metrology_model

set_system (border_shape_models, false) read_image (Image, D:/图像文件/调试图片/调试图片/cam220230726182355309.bmp) * draw_rectangle2 (3600, Row4, Column5, Phi3, Length12, Length22) Rect1Row:1010.37 Rect1Col:1189.15 phi:-0.188 RectLength1:450.531 RectLengt…

uni-app修改头像和个人信息

效果图 代码&#xff08;总&#xff09; <script setup lang"ts"> import { reqMember, reqMemberProfile } from /services/member/member import type { MemberResult, Gender } from /services/member/type import { onLoad } from dcloudio/uni-app impor…

Docker-阿里云镜像配置

1、创建文件 vi /etc/docker/daemon.json 刚安装的docker一般没有docker/daemon.json这些&#xff0c;需要自己新建 2、文件中添加内容 { "registry-mirrors": ["https://m3e4jmm0.mirror.aliyuncs.com"] } 3、重启 重新加载配置&#xff1a; systemct…

Google的Ndk-Sample学习笔记之一(hello-jniCallback)

前言: 近段时间因为项目的需求,需要使用JNI,所以下载了Google的Ndk-Sample学习下,准备记录 下来,留给后期自己查看 问题点一:JNI_OnLoad方法必须返回JNI的版本 JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {JNIEnv *env;memset(&g_ctx, 0, sizeof(g_…

ABAP CDS 常用语法

文章目录 1.什么是abap cdsadap cds的优点 2.常用cds语法常用函数一 数值函数1.绝对值2. 最小整数不小于arg的值3.两个参数相除4.两个数相除切保留小数位5.最小整数不大于arg的值6.取除数的余数 二 字符串函数1.拼接字符2.替换字符3.截取字符串 三 常用的分支语句1.CASE 表达式…

亚马逊API:快速查询全球商品数据的技巧!

了解亚马逊API的限制和要求&#xff1a;在使用亚马逊API之前&#xff0c;您需要了解其限制和要求&#xff0c;例如请求频率限制、认证要求等。确保您遵循了API的使用条款&#xff0c;以避免不必要的麻烦。使用合适的亚马逊API服务&#xff1a;亚马逊提供了多个API服务&#xff…