转载地址:https://www.linuxidc.com/Linux/2017-10/147521.htm
    
   
    
     Linux kernel 3.10.49+
    
   
   
    pinctrl驱动的platform注册就不说了,
    
    无非就是platform_driver_register这个入口,
    
    最后匹配到合适的设备后调用struct platform_driver 的probe函数.
   
    
     这里说说, pinctl io复用关系(pinmux)的是怎么通过device tree source(dts)设置的.
     
     1. 首先,当然是看pinctrl驱动的probe函数(这相当于驱动初始化的入口):
     
     drivers/pinctrl/pinctrl-xxxxxx.c : xxxxxx_pinctrl_probe(…)
     
     xxxxxx_pinctrl_probe(…) –> pinctrl_register(…)
    
   
    
     2. drivers/pinctrl/core.c : pinctrl_register(…)
     
     pinctrl_register(…) –> pinctrl_get(…)
    
   
    
     3. drivers/pinctrl/core.c : pinctrl_get(…)
     
     pinctrl_get(…) –> create_pinctrl(…)
    
   
    
     4. drivers/pinctrl/core.c : create_pinctrl(…)
     
     create_pinctrl(…) –> pinctrl_dt_to_map(…)
    
   
    
     5. drivers/pinctrl/devicetree.c : pinctrl_dt_to_map(…)
     
     pinctrl_dt_to_map(…) –> dt_to_map_one_config(…)
    
   
    
     6. drivers/pinctrl/devicetree.c : dt_to_map_one_config(…)
     
     dt_to_map_one_config(…) –> ops->dt_node_to_map(…) // 回调函数. 第7~10步是进入到回调后的一系列初始化.
    
   
    
     7. ops->dt_node_to_map 就是 drivers/pinctrl/pinctrl-xxxxxx.c 中 struct pinctrl_ops 的 dt_node_to_map成员函数指针,
     
     也就是struct pinctrl_ops xxxxxx_pinctrl_ops->dt_node_to_map  = xxxxxx_pinctrl_dt_node_to_map;
    
   
    
     8.  drivers/pinctrl/pinctrl-xxxxxx.c : xxxxxx_pinctrl_dt_node_to_map(…)
     
     xxxxxx_pinctrl_dt_node_to_map(…) –> 轮询调用 xxxxxx_pinctrl_dt_subnode_to_map(…)
     
     轮询的内容: struct device_node *np 其中一个就是 dts文件里pinmuxing node设备, 而pinmuxing node设备有7个子node(看例子):
     
     如: arm926u, i2c0, i2c1等.
     
     state_default: pinmuxing {
     
     
     arm926u {
     
     
     xxx,function = “arm926u”;
     
     xxx,group = “arm926u”;
     
     };
     
     i2c0 {
     
     xxx,function = “i2c”;
     
     xxx,group = “i2c0_pos_0”;
     
     };
     
     i2c1 {
     
     
     xxx,function = “i2c”;
     
     xxx,group = “i2c1”;
     
     };
     
     i2c2 {
     
     
     xxx,function = “i2c”;
     
     xxx,group = “i2c2”;
     
     };
     
     uart0 {
     
     
     xxx,function = “uart”;
     
     xxx,group = “uart0_pos_0”;
     
     };
     
     uart1 {
     
     
     xxx,function = “uart”;
     
     xxx,group = “uart1_pos_0”;
     
     };
     
     wdt {
     
     
     xxx,function = “wdt”;
     
     xxx,group = “wdt”;
     
     };
     
     };
    
   
    
     9. drivers/pinctrl/pinctrl-xxxxxx.c : xxxxxx_pinctrl_dt_subnode_to_map(…)
     
     在这里有:
     
     ret = of_property_read_string(np, “xxx,function”, &function);  // 哈哈, 解析dts node设备属性
     
     ret = of_property_read_string(np, “xxx,group”, &group);
     
     reserve_map(…) // allocate map内存
     
     最后调用 add_map_mux(…);
    
   
    
     10. drivers/pinctrl/pinctrl-xxxxxx.c : add_map_mux(…)
     
     (*map)[*num_maps].type = PIN_MAP_TYPE_MUX_GROUP;  //特别注意这个type, 后续用到
     
     (*map)[*num_maps].data.mux.group = group;        // group只是个字符串, 如:i2c0_pos_0
     
     (*map)[*num_maps].data.mux.function = function;  // function只是个字符串, 如:i2c
     
     (*num_maps)++;
    
   
    
     11. 回调ops->dt_node_to_map完成, 回到第6步继续运行.
     
     drivers/pinctrl/devicetree.c : 运行dt_remember_or_free_map(…);
    
   
    
     12. drivers/pinctrl/devicetree.c : dt_remember_or_free_map(…)
     
     dt_remember_or_free_map(…) –> pinctrl_register_map(…)
    
   
    
     13. drivers/pinctrl/core.c : pinctrl_register_map(…)
     
     判断一下PIN_MAP_TYPE_MUX_GROUP
     
     pinctrl_register_map(…) –> list_add_tail(&maps_node->node, &pinctrl_maps)  // pinctrl_maps 是全局变量: LIST_HEAD(pinctrl_maps);
    
   
    
     ######### 到这里, create_pinctrl(…) 的 pinctrl_dt_to_map(…) 函数已运行完成. #########
    
   
    
     14. 回调pinctrl_dt_to_map完成, 回到第4步继续运行. 还是在create_pinctrl(…)函数里.
     
     create_pinctrl(…) –> add_setting(…)
    
   
    
     15. drivers/pinctrl/core.c : add_setting(…)
     
     switch (map->type) {
     
     
     case PIN_MAP_TYPE_MUX_GROUP:
     
     ret = pinmux_map_to_setting(map, setting);
     
     break;
     
     }
     
     add_setting(…) –> pinmux_map_to_setting(…)
    
   
    
     16. drivers/pinctrl/pinmux.c : pinmux_map_to_setting(…)
     
     pinmux_map_to_setting(…) –> pmxops->get_function_groups(…)
    
   
    
     17. pmxops->get_function_groups(…) 就是 drivers/pinctrl/pinctrl-xxxxxx.c 中 struct pinmux_ops 的 get_function_groups成员函数指针,
     
     也就是struct pinmux_ops xxxxxx_pinmux_ops->get_function_groups  = xxxxxx_get_groups;
     
     在xxxxxx_get_groups(…)函数里:可以取到 xxxxx_groups[] = {…};的字符串数值.
    
   
    
     ret = pinmux_func_name_to_selector(pctldev, map->data.mux.function);
     
     // pinmux_func_name_to_selector(…) {  // 函数实现
     
     // …
     
     //    while (selector < nfuncs) {
     
     
     //        const char *fname = ops->get_function_name(pctldev,
     
     //                selector);            // ops->get_function_name 就是struct pinmux_ops的get_function_name 取到 i2c
    
   
    
     //        if (!strcmp(function, fname))  // function: map->data.mux.function这个就是dts的 xxx,function = “i2c”;
     
     //            return selector;  // fname:得到const struct xxxxxx_function xxxxxx_functions[] 第几个是i2c,
     
     // 所以, 代码里的 function 与 group 必须是一一对应的.
    
   
    
     //        selector++;
     
     //    }
     
     // }
     
     // …
     
     setting->data.mux.func = ret;
     
     ret = pmxops->get_function_groups(pctldev, setting->data.mux.func,
     
     &groups, &num_groups);
     
     // groups 等于 fname##_groups 如:const char * const i2c_groups[] = { “i2c0_pos_0”, “i2c0_pos_1”, “i2c1”, “i2c2”}
     
     group = map->data.mux.group;  // xxx,group = “i2c0_pos_0”;  //注意: 凡是map相关的, 很可能是dts的内容
     
     for (i = 0; i < num_groups; i++) {
     
     
     if (!strcmp(group, groups[i])) {
     
     found = true;
     
     break;
     
     }
     
     }
     
     // dts的 类似于xxx,group = “i2c0_pos_0” 与通过get_function_groups获取到代码的 const struct xxxxxx_function xxxxxx_functions[]全局变量.
     
     // 两个作对比, 得到setting->data.mux.group;
    
   
    
     ret = pinctrl_get_group_selector(pctldev, group);
     
     // pinctrl_get_group_selector(struct pinctrl_dev *pctldev,
     
     const char *pin_group) {  // 函数实现
     
     // …
     
     // while (group_selector < ngroups) {
     
     
     //    const char *gname = pctlops->get_group_name(pctldev,
     
     //                            group_selector);  // pctlops->get_group_name 就是 struct pinctrl_ops的get_group_name
     
     //    if (!strcmp(gname, pin_group)) {  // pin_group: 是 xxx,group = “i2c0_pos_0”;
     
     // gname: 是 代码里的全局变量 const struct xxxxxx_group xxxxxx_groups[];
     
     //        dev_dbg(pctldev->dev,
     
     //            “found group selector %u for %s\n”,
     
     //            group_selector,
     
     //            pin_group);
     
     //        return group_selector;
     
     //    }
    
   
    
     //    group_selector++;
     
     // }
     
     // …
    
   
    
     setting->data.mux.group = ret;  // 得到setting->data.mux.group,后面给xxxxxx_enable使用(设置控制寄存器)
     
     // 相当于, 我只要在dts中设置xxx,group = “i2c0_pos_0”, pinctrl子系统就会找到对应的寄存器设置.
    
   
    
     
     ######### 到这里, create_pinctrl(…) 的 add_setting(…) 函数已运行完成. #########
    
   
    
     
     ######### 到这里, pinctrl_register(…) 的 pinctrl_get(…) 函数已运行完成. #########
    
   
    
     18. 回调pinctrl_get完成, 回到第2步继续运行. 还是在pinctrl_register(…)函数里.
     
     pinctrl_register(…) –> pinctrl_select_state(…)
     
     switch (setting->type) {
     
     
     case PIN_MAP_TYPE_MUX_GROUP:  // 用到了.
     
     ret = pinmux_enable_setting(setting);
     
     break;
     
     …
     
     }
    
   
    
     19. drivers/pinctrl/pinmux.c : pinmux_enable_setting(…)
     
     pinmux_enable_setting(…) –> ops->enable(…) // 哈哈, 又是ops,回调函数,第19~20步是进入到回调后的一系列初始化.
     
     ret = ops->enable(pctldev, setting->data.mux.func,
     
     setting->data.mux.group);
    
   
    
     
     20. ops->enable 就是 drivers/pinctrl/pinctrl-xxxxxx.c 中 struct pinmux_ops 的 enable成员函数指针,
     
     也就是struct pinmux_ops xxxxxx_pinmux_ops->enable  = xxxxxx_enable;
     
     在xxxxxx_enable(…)函数里:可以设置控制寄存器的值, 作为IO复用设置(这函数是内核运行完成后,应用程序修改时用到的.), 用作gpio, 还是i2c等.
    
   
    
     ######### 到这里, pinctrl_register(…) 的 pinctrl_select_state(…) 函数已运行完成. #########
    
   
    
    
   
    
     
     ##############################################################################################
     
     重要结构体:
     
     1). struct pinctrl_desc: struct platform_driver的probe函数的pinctrl_register需要使用到
     
     struct pinctrl_dev *pinctrl_register(struct pinctrl_desc *pctldesc,
     
     struct device *dev, void *driver_data);
    
   
    
     2). struct pinctrl_ops: struct pinctrl_desc结构体需要使用到.
     
     .get_groups_count = 需赋函数指针, –|
     
     .get_group_name = 需赋函数指针,    |  这三个函数, 需要生成一个全局变量的结构体, 指定gpio引脚控制寄存器的位移和组需要用到的引脚号.
     
     .get_group_pins = 需赋函数指针,  –|
     
     .dt_node_to_map = 需赋函数指针, ——|
     
     .dt_free_map = 需赋函数指针,    ——|  这两个是解析dts文件的复用信息pinmuxing到内存map 和 析构map
    
   
    
     
     3). struct pinmux_ops: struct pinctrl_desc结构体需要使用到.
     
     .gpio_request_enable = 需赋函数指针,
     
     .gpio_disable_free = 需赋函数指针,
     
     .request = 需赋函数指针,
     
     .free = 需赋函数指针,
     
     .get_functions_count = 需赋函数指针,  –|
     
     .get_function_name = 需赋函数指针,    –| 这三个函数, 是直接解析dts, 用到的function 和 group, 通过function名字, 找到 group的名字(可能有多个)
     
     .get_function_groups = 需赋函数指针,  –|                  再通过 group 的名字去找到gpio引脚控制寄存器的信息, 最后通过enable回调函数设置.
     
     .enable = 需赋函数指针,
     
     .disable = 需赋函数指针,
    
   
    
     4). struct pinctrl_pin_desc 所有引脚号.
     
     5). 自定义group结构体:
     
     5-1). group的名字(也就是io复用的名字)(dts编写时, 需要在这里找得到),
     
     5-2). 复用io数(如i2c, 需要使用两个io).
     
     5-3). 控制寄存器地址, 和使用哪几位.
     
     6). 自定义function结构体:
     
     6-1). function的名字(dts编写时, 需要在这里找得到),
     
     6-2). group的名字(可以有很多个, 如i2c1, i2c2等, 但也必须在自定义group结构体里找得到)
    
   
    
     ##############################################################################################
     
     pinctrl 运行原理:
     
     1) 读取dts: 先读入dts的pinmuxing节点的信息到map;
     
     2) dts的子节点的function 和 自定义function结构体的function的名字匹配, 得到自定义function结构体的下标, 放入Setting变量的func:
     
     3) 由自定义function结构体的下标, 得到自定义function结构体的group的名字和数量;
     
     4) 判断 dts的子节点的group 是否在自定义function结构体的group的名字里面, 如果是, 运行第5步, 否就运行第二步匹配dts下一个子节点的function;
     
     5) dts的子节点的group 和 自定义group结构体的group的名字匹配, 得到自定义group结构体的下标, 放入Setting变量的group;
     
    
   
    
     6) 通过Setting变量的func和group这两个下标调用struct pinmux_ops的enable回调函数. 哈哈, 络于可以设置寄存器了
    
   
    
     重要结构体:
     
     struct pinctrl_desc {                      // pinctrl_register(…) 使用到.
     
     const char *name;                      // 设备的名字platform_device传过来, 注意:不是node(dts 节点)的名字, 是xxxxx.*或a8000000.xxxxx
     
     struct pinctrl_pin_desc const *pins;    // 引脚枚举{枚举号, 引脚名字}  // 全局变量赋值  —|
     
     unsigned int npins;                    // 引脚总数                    //              —| 这两个pinctrl_register_pins会使用到.
     
     const struct pinctrl_ops *pctlops;      // 必须                        // 全局变量赋值
     
     const struct pinmux_ops *pmxops;        // 可选(引脚复用时,需选上)      // 全局变量赋值
     
     const struct pinconf_ops *confops;      // 可选(一般不用.)              // 全局变量赋值
     
     struct module *owner;                  // THIS_MODULE
     
     };
    
   
    
     struct pinctrl_dev      : pinctrl设备结构体(包含struct device通用属性, 其它是pinctrl独有属性)
     
     struct platform_device  : platform设备结构体(包含struct device通用属性, 其它是pinctrl独有属性)
     
     // 用of 解析的dts设备, 一开始都认为是platform设备, 所以都使用platform_driver_register来注册, probe回传platform_device结构体
     
     // 如: gpio, pinctrl
     
     // pinctrl 会通过pinctrl_register把转platform_device换成pinctrl_dev. (通用属性, 直接赋值过来, 其它重新初始化.)
    
   
    
     重要变量:
     
     pinctrl_maps: 这个是全局变量, 虽然与struct pinctrl_maps同名, 由LIST_HEAD(pinctrl_maps)生成
     
     // 在drivers/pinctrl/core.c路径下.由pinctrl_register_map(…)函数使用.
     
     // 保存引脚控制句柄(struct pinctrl_dt_map)列表, 每个设备(dts带有pinctrl-0和pinctrl-names两个属性)驱动注册时, 都会过来全部保存.
     
     // 如果节点有pinctrl-0和pinctrl-names两个属性, 则说明这个节点有复用信息,
     
     // 所以这个节点驱动注册时去轮询dts时, 保存这个节点的子节点的io复用的group, function两个字符串信息.
     
     //
     
     // struct pinctrl_map 包含于struct pinctrl_maps, 是专门保存group, function两个字符串信息的容器.
     
     //
     
     // 如果dts中有两个节点带有pinctrl-0, 则pinctrl_maps列表中就会有两个有效struct pinctrl_dt_map的数据.
     
     // 简单地说, 就复用信息映射
    
   
    
     pinctrl_list: 这个是全局变量, 由static LIST_HEAD(pinctrl_list)生成
     
     // 在drivers/pinctrl/core.c路径下.由create_pinctrl(…)函数使用.
     
     // 保存引脚控制句柄(struct pinctrl)列表, 每个设备驱动注册时, 都会过来保存一次.
     
     // struct pinctrl有两个比较重要的成员states, dt_maps;
     
     // dt_maps如果节点dts带有pinctrl-0(也就是说是dts描述复用的设备), 那么dt_maps与struct pinctrl_dt_map一样, 否则为空.
     
     // states如果节点dts带有pinctrl-0(也就是说是dts描述复用的设备), 那么states与pinctrl-names的值一样, 一般来说只有一个”default”值, 否则为空(如:gpio为空)
    
   
    
     ##########################################################################################################################################
    
   
    
     重要函数:
     
     static inline void platform_set_drvdata(struct platform_device *pdev, void *data);
     
     // 设置platform_device的私有数据(自定义数据), 实际上是保存私有指针到pdev->dev->p->driver_data
     
     // pdev->dev                        :是struct device通用属性
     
     // pdev->dev->p                    :是struct device 的 struct device_private 结构体指针
     
     // pdev->dev->p->driver_data        :可以存放自定义数据的指针
    
   
    
     static inline void *platform_get_drvdata(const struct platform_device *pdev);
     
     // 获取platform_device的私有数据(自定义数据的指针)
    
   
    
     static inline const char *dev_name(const struct device *dev)
     
     // 获取struct device的name, 因为struct device没有name成员, 可以用这个.
    
   
    
     static struct pinctrl_state *create_state(struct pinctrl *p,
     
     const char *name);
     
     // 参数:
     
     // p: 就是引脚控制句柄,
     
     // name: pinctrl-names的值, 或PINCTRL_STATE_DEFAULT
    
   
    
     static struct pinctrl_state *find_state(struct pinctrl *p,
     
     const char *name);
     
     // 参数:
     
     // p: 就是引脚控制句柄,
     
     // name: pinctrl-names的值, 或PINCTRL_STATE_DEFAULT, 一般为PINCTRL_STATE_DEFAULT
    
   
    
     struct pinctrl_state *pinctrl_lookup_state(struct pinctrl *p,
     
     const char *name);
     
     // 参数:
     
     // p: 就是引脚控制句柄,
     
     // name: pinctrl-names的值, 或PINCTRL_STATE_DEFAULT, 一般为PINCTRL_STATE_DEFAULT
    
   
    
     
     ##########################################################################################################################################
    
   
    
     其它, 重要函数:
     
     struct list_head;  // 只是一个环形链表指针管理工具, 构建结构体包含它, 就可以通过container_of宏访问到构建的结构体变量.
     static inline void list_add(struct list_head *new, struct list_head *head);
     
     // 环形链表, 把 new 插入到 head 的后面
     
     // 如 head == h 10 20
     
     // 如 1 –> head == h 1 10 20
     
     // 如 2 –> head == h 2 1 10 20
    
   
    
     static inline void list_add_tail(struct list_head *new, struct list_head *head)
     
     // 环形链表, 把 new 插入到 head 的前面
     
     // 如 head == h 10 20
     
     // 如 1 –> head == 1 h 10 20      ==> [ h 10 20 1 ]
     
     // 如 2 –> head == 2 h 10 20 1    ==> [ h 10 20 1 2 ]
    
   
    
     重要宏:
     
     LIST_HEAD(name)
     
     // 宏: 生成以name为名字的全局list_head变量, 并初始化成员next, prev指向自已
    
   
    
     static inline void INIT_LIST_HEAD(struct list_head *list)
     
     // 初始化已经存在的list变量的成员next, prev指向自已
    
   
    
     for_each_maps(maps_node, i, map)
     
     // 参数定义如下:
     
     // struct pinctrl_maps *maps_node    // 只是提供struct pinctrl_maps这样一个结构体, 由typeof使用.(宏内部使用)
     
     // int i;                            // 作为一个interator使用.(宏内部使用)
     
     // struct pinctrl_map const *map;    // 轮询pinctrl_maps这个全局变量列表, 得到每个列表结节的成员(struct pinctrl_map).
    
   
 
