大望路做网站的公司,网站建设公司做销售前景好不好,网站怎么做才会有收录,wordpress环境文件包瑞芯微RK3568芯片是一款定位中高端的通用型SOC#xff0c;采用22nm制程工艺#xff0c;搭载一颗四核Cortex-A55处理器和Mali G52 2EE 图形处理器。RK3568 支持4K 解码和 1080P 编码#xff0c;支持SATA/PCIE/USB3.0 外围接口。RK3568内置独立NPU#xff0c;可用于轻量级人工…瑞芯微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的相关知识和疑问就都讲解和解答完成了。