Hi3519-pinctrl驱动开发③consumer driver与pinctrl子系统交互
来源:互联网 发布:工业革命 知乎 编辑:程序博客网 时间:2024/05/21 19:32
前一篇文章介绍了如果创建consumer driver到pinctrl driver的mapping table,这个mapping table就是系统的配置表,在系统启动之初注册到pinctrl sub system中去,貌似是在pinctrl driver注册之前就注册了mapping table了。既然已经有了mapping table,那我们假设pinctrl driver也已经“编写完成”(假设可以用了),这时候编写一个设备驱动的时候需要使用pinctrl sub system提供的服务,这时候设备驱动如何和pinctrl sub system交互呢?
有一个概念需要理解,就是“state”,也就是“状态”,每个设备对应第一个引脚组,继续以spi0设备为例,假设spi0设备对应的引脚组有两个,分别是PA0、1、2、3和PB5、6、7、8。state表示的就是设备使用的引脚组中引脚的状态,往常单片机开发中没有这个概念,但是在linux中为了提供足够的便利性和功能支持使用了state这个概念,具体来说当设备spi0正常运行的时候引脚状态处于正常状态,一般叫做default状态,当spi0设备处于关闭或者说低功耗模式下的时候引脚状态处于低功耗状态,一般叫做idle状态或者sleep状态(引脚的低功耗状态可能就是高阻态)。这样看来一个设备的pins可以处于不同的状态,pinctrl sub system提供了一种机制:pinctrl state holder,这个holder是一个容器,每一个设备都对应一个pinctrl state holder,用来存放设备拥有的所有states,pinctrl state holder结构体的定义如下:
struct pinctrl { struct list_head node;--系统中的所有device的pin control state holder被挂入到了一个全局链表中 struct device *dev;---该pin control state holder对应的device struct list_head states;----该设备的所有的状态被挂入到这个链表中 struct pinctrl_state *state;---当前的pin control state struct list_head dt_maps;----mapping table struct kref users;------reference count };
pinctrl state holder结构体的名称为“pinctrl”,而pinctrl驱动的描述结构体的名称为“pinctrl_desc”,真的很郁闷为什么这么命名,我觉得可以是“pinctrl_state_holder”和“pinctrl”,这样对于理解会方便很多。
pinctrl state holder结构体中的states元素存放的就是device的state链表,state元素存放的是当前device处于的状态。说到这里state显得很神秘,state是由结构体pinctrl_state 描述的:
struct pinctrl_state { struct list_head node;---链表元素 const char *name;---state的名称 struct list_head settings;---设置};
pinctrl_state 前两个元素很好理解,最后一个settings元素表示的是要设置成这个state的话要进行的配置,settings也是一个链表,也就是有多个setting。setting是结构体struct pinctrl_setting:
struct pinctrl_setting { struct list_head node;---链表元素 enum pinctrl_map_type type;---map type struct pinctrl_dev *pctldev;---pinctrl驱动 const char *dev_name;---使用这个state的设备名 union { struct pinctrl_setting_mux mux; struct pinctrl_setting_configs configs; } data;};
这个结构体和struct pinctrl_map结构体很像,type为PIN_MAP_TYPE_MUX_GROUP时data为mux,struct pinctrl_setting_mux的定义如下:
struct pinctrl_setting_mux { unsigned group;---the group selector to program unsigned func;---the function selector to program};
其中group就是引脚组的索引,func就是功能的索引。state的组织原理图如下图:
state概念介绍完了,那么说每个device对应的pinctrl state holder中的states中的settings是怎么来的,难道说是device自己定义的?显然不能,这样的话驱动会有太多没用的程序,而且可移植性很差。具体是怎么创建device的states和state中的settings呢?我也没研究过,我猜测是这样的:mapping table在系统启动之初就建立好了,注册到pinctrl sub system中,在建立pinctrl state holder的时候pinctrl子系统会根据对应的mapping table中的mapping entry创建states和settings,先假设是这么回事。现在已经“知道了”states和settings是在建立pinctrl state holder的时候创建的,那么pinctrl state holder是如何创建的呢?
pinctrl state holder是动态定义的,且并不是每个device都对应一个pinctrl state holder,因为有的device是不用引脚的。需要引脚的device需要获取属于自己的pinctrl state holder,使用的pinctrl sub system接口函数是devm_pinctrl_get和pinctrl_get,前者是后者的resource managed版本。单看后者pinctrl_get函数:
868 struct pinctrl *pinctrl_get(struct device *dev)869 {870 struct pinctrl *p;871 872 if (WARN_ON(!dev))873 return ERR_PTR(-EINVAL);874 875 /*876 * See if somebody else (such as the device core) has already877 * obtained a handle to the pinctrl for this device. In that case,878 * return another pointer to it.879 */880 p = find_pinctrl(dev);881 if (p != NULL) {882 dev_dbg(dev, "obtain a copy of previously claimed pinctrl\n");883 kref_get(&p->users);884 return p;885 }886 887 return create_pinctrl(dev);888 }
第880行中的find_pinctrl函数用来查找当前系统是否已经定义了该device的pinctrl state holder,如果没有定义的话就调用887行中的 create_pinctrl函数创建该device的pinctrl state holder。create_pinctrl如下:
788 static struct pinctrl *create_pinctrl(struct device *dev) 789 { 790 struct pinctrl *p; 791 const char *devname; 792 struct pinctrl_maps *maps_node; 793 int i; 794 struct pinctrl_map const *map; 795 int ret; 796 797 /* 798 * create the state cookie holder struct pinctrl for each 799 * mapping, this is what consumers will get when requesting 800 * a pin control handle with pinctrl_get() 801 */ 802 p = kzalloc(sizeof(*p), GFP_KERNEL); 803 if (p == NULL) { 804 dev_err(dev, "failed to alloc struct pinctrl\n"); 805 return ERR_PTR(-ENOMEM); 806 } 807 p->dev = dev; 808 INIT_LIST_HEAD(&p->states); 809 INIT_LIST_HEAD(&p->dt_maps); 810 811 ret = pinctrl_dt_to_map(p); 812 if (ret < 0) { 813 kfree(p); 814 return ERR_PTR(ret); 815 } 816 817 devname = dev_name(dev); 818 819 mutex_lock(&pinctrl_maps_mutex); 820 /* Iterate over the pin control maps to locate the right ones */ 821 for_each_maps(maps_node, i, map) { 822 /* Map must be for this device */ 823 if (strcmp(map->dev_name, devname)) 824 continue; 825 826 ret = add_setting(p, map); 827 /* 828 * At this point the adding of a setting may: 829 * 830 * - Defer, if the pinctrl device is not yet available 831 * - Fail, if the pinctrl device is not yet available, 832 * AND the setting is a hog. We cannot defer that, since 833 * the hog will kick in immediately after the device 834 * is registered. 835 * 836 * If the error returned was not -EPROBE_DEFER then we 837 * accumulate the errors to see if we end up with 838 * an -EPROBE_DEFER later, as that is the worst case. 839 */ 840 if (ret == -EPROBE_DEFER) { 841 pinctrl_free(p, false); 842 mutex_unlock(&pinctrl_maps_mutex); 843 return ERR_PTR(ret); 844 } 845 } 846 mutex_unlock(&pinctrl_maps_mutex); 847 848 if (ret < 0) { 849 /* If some other error than deferral occured, return here */ 850 pinctrl_free(p, false); 851 return ERR_PTR(ret); 852 } 853 854 kref_init(&p->users); 855 856 /* Add the pinctrl handle to the global list */ 857 mutex_lock(&pinctrl_list_mutex); 858 list_add_tail(&p->node, &pinctrl_list); 859 mutex_unlock(&pinctrl_list_mutex); 860 861 return p; 862 }
简单看一下程序,802行分配pinctrl state holder内存空间,811行使用函数pinctrl_dt_to_map创建mapping table,这是使用DTS的方式创建的,我们使用的是Machine Driver的方式创建的,结果都是一样的,都是创建一个mapping table,只是DTS方式更加灵活方便,不需要修改内核代码就能系统支持不同的Board。这里有个疑问,没有使用DTS方式的话pinctrl_dt_to_map函数是不是会返回错误呢?这样就会在814行返回了,返回的话后面的初始化就没有得到执行,我看了一下pinctrl_dt_to_map函数的部分源码:
175 int pinctrl_dt_to_map(struct pinctrl *p)176 {177 struct device_node *np = p->dev->of_node;178 int state, ret;179 char *propname;180 struct property *prop;181 const char *statename;182 const __be32 *list;183 int size, config;184 phandle phandle;185 struct device_node *np_config;186 187 /* CONFIG_OF enabled, p->dev not instantiated from DT */188 if (!np) {189 if (of_have_populated_dt())190 dev_dbg(p->dev,191 "no of_node; not parsing pinctrl DT\n");192 return 0;193 }194 195 /* We may store pointers to property names within the node */196 of_node_get(np);......
117行中获取p->dev->of_node,188行判断np是否为null,如果为null表示没有使用Device Tree机制,同时返回0表示没有错误。回到create_pinctrl函数,这样一来pinctrl_dt_to_map并没有完成解析DT来创建mapping table的任务,因为根本没有DT。接下里821行的“for_each_maps(maps_node, i, map)”其实就是遍历了系统全局变量pinctrl_maps链表中的每个pinctrl_maps,宏展开后是这样的:
list_for_each_entry(maps_node, &pinctrl_maps, node) for (i=0,map=&maps_node->maps[i];i<maps_node->num_maps;i++,map=&maps_node>maps[i])
list_for_each_entry的含义参见文章:http://blog.csdn.net/tq384998430/article/details/73188601,简单来说就是list_for_each_entry宏中maps_node是一个迭代变量,&pinctrl_maps是链表头指针,node是结构体中的元素名称。整体意思就是从链表pinctrl_maps中挨个获取pinctrl_maps元素赋值给maps_node,然后循环将maps_node中的元素赋值给map进入循环中执行。注意这里两个pinctrl_maps的区别,一个pinctrl_maps是core.c文件中定义的链表全局变量:
59:LIST_HEAD(pinctrl_maps);
另一个是结构体struct pinctrl_maps。前者pinctrl_maps链表中的元素都是struct pinctrl_maps类型。
下面再看create_pinctrl函数的826行,add_setting,很显然这是通过map元素来创建pinctrl state holder中的state和settings,add_setting函数源码就不看了,意图很明显。经过list_for_each_entry循环和第二层的for循环后将所有与创建pinctrl state holder的device相关的maps都生成了相应的states和settings,这样consumer driver就能使用这些个states了。下面来说具体怎么使用定义好了的state holder中的states。
前面使用pinctrl_get已经创建了device的pinctrl state holder,并且根据mapping table初始化了pinctrl state holder中的states和settings(对应的devm_pinctrl_put和pinctrl_put两个函数用于释放pinctrl state holder资源)。现在假设一个场景是spi0设备驱动从pinctrl sub system中获取到了自己的pinctrl state holder,然后它要设置自己需要的引脚的状态到default状态,那么它可以使用函数pinctrl_lookup_state,函数原型为:
struct pinctrl_state *pinctrl_lookup_state(struct pinctrl *p, const char *name);
这个函数根据state name在pin control state holder找到对应的pin control state。具体的state是各个device自己定义的,不过pin control subsystem自己定义了一些标准的pin control state,定义在pinctrl-state.h文件中:
#define PINCTRL_STATE_DEFAULT "default" #define PINCTRL_STATE_IDLE "idle" #define PINCTRL_STATE_SLEEP "sleep"
调用pinctrl_lookup_state示例:
dev->pins->default_state = pinctrl_lookup_state(dev->pins->p,PINCTRL_STATE_DEFAULT);
获取到了default_state之后可以调用pinctrl_select_state函数:
int pinctrl_select_state(struct pinctrl *p, struct pinctrl_state *state);
这个函数用来选中一个特定的state,意思就是设置引脚成该state所描述的状态,这个设置过程就是由pinctrl驱动完成的了。
- Hi3519-pinctrl驱动开发③consumer driver与pinctrl子系统交互
- Hi3519-pinctrl驱动开发④pinctrl driver接口
- Hi3519-pinctrl驱动开发①开发环境搭建
- Hi3519-pinctrl驱动开发②创建mapping table
- PINCTRL子系统
- PINCTRL子系统
- pinctrl
- linux pinctrl驱动
- linux pinctrl子系统实例说明
- Linux pinctrl子系统实例分析
- gpio子系统和pinctrl子系统(一)
- gpio子系统和pinctrl子系统(二)
- gpio子系统和pinctrl子系统(三)
- gpio子系统和pinctrl子系统(上)
- gpio子系统和pinctrl子系统(上)
- Linux内核中的pinctrl子系统应用实例
- 设备驱动中的pinctrl(kernel-4.7)
- PINCTRL介绍
- 正则表达式学习笔记 Chapter01--入门
- 【LeetCode】3-Sum
- Android开发之ANR
- QS Network(最小生成树)
- 排序算法系类-交换之冒泡优化
- Hi3519-pinctrl驱动开发③consumer driver与pinctrl子系统交互
- 226. Invert Binary Tree
- 学习笔记整理1——零碎小知识点
- 静态变量Static
- select服务器的实现
- 使用python的hdfs包操作分布式文件系统(HDFS)
- leejianjun的博客 PHP生成word并可下载
- missing: vtable for __cxxabiv1::__si_class_type_info
- c51上跑smallrtos 之4x4 矩阵键盘任务