【Linux基础系列之】pinctrl系统

来源:互联网 发布:苹果cms监控软件手机版 编辑:程序博客网 时间:2024/06/06 14:12

  pinctrl子系统用于控制管脚管理soc的管脚,它通常可以以一组寄存器的形式存在,用于使能独立或成组管脚的复用、设置负载电流、设置驱动能力等;


(一) pinctrl系统概述

(1)基本概念

  管脚定义:管脚(也代指pad、金手指、ball,依据其封装不同)输入/输出线使用无符号整型数表示,范围为0到maxpin。这个数字空间是每个管脚控制器独有的,这样,一个系统中可能有几个此类的数字空间。管脚空间可以是稀疏的,空间中可能存在一些并没有管脚存在间隙。用struct pinctrl_dev实例化一个管脚控制器,同时会注册一个描述符到管脚控制架构,这个描述符包含一组为它控制管脚的管脚描述符(struct pinctrl_desc).

128 struct pinctrl_desc {129     const char *name;130     const struct pinctrl_pin_desc *pins;131     unsigned int npins;132     const struct pinctrl_ops *pctlops;133     const struct pinmux_ops *pmxops;134     const struct pinconf_ops *confops;135     struct module *owner;141 };

  通过struct pin_desc来描述每个物理pin脚:

147 struct pin_desc {148     struct pinctrl_dev *pctldev;149     const char *name;150     bool dynamic_name;151     /* These fields only added when supporting pinmux drivers */152 #ifdef CONFIG_PINMUX153     unsigned mux_usecount;154     const char *mux_owner;155     const struct pinctrl_setting_mux *mux_setting;156     const char *gpio_owner;157 #endif158 };

  pin control subsystem的主要功能包括:

(1)管理系统中所有可以控制的pin。在系统初始化的时候,枚举所有可以控制的pin,并标识这些pin。

(2)管理这些pin的复用(Multiplexing)。对于SOC而言,其引脚除了配置成普通GPIO之外,若干个引脚还可以组成一个pin group,形成特定的功能。pin control subsystem要管理所有的pin group。

(3)配置这些pin的特性。例如配置该引脚上的pull-up/down电阻,配置drive strength等

下面依次介绍几个重要元素:


(a)Pin groups

  有时需要将很多pin组合在一起,以实现特定的功能,例如SPI接口、I2C接口等。因此pin controller需要以group为单位,访问、控制多个pin,这就是pin groups, 通过 pinctrl_ops定义的接口来访问操作group pin :

 90 struct pinctrl_ops { 91     int (*get_groups_count) (struct pinctrl_dev *pctldev); 92     const char *(*get_group_name) (struct pinctrl_dev *pctldev, 93                        unsigned selector); 94     int (*get_group_pins) (struct pinctrl_dev *pctldev, 95                    unsigned selector, 96                    const unsigned **pins, 97                    unsigned *num_pins); 98     void (*pin_dbg_show) (struct pinctrl_dev *pctldev, struct seq_file *s, 99               unsigned offset); 100     int (*dt_node_to_map) (struct pinctrl_dev *pctldev,101                    struct device_node *np_config,102                    struct pinctrl_map **map, unsigned *num_maps);103     void (*dt_free_map) (struct pinctrl_dev *pctldev,104                  struct pinctrl_map *map, unsigned num_maps);105 };

get_groups_count():获取系统中pin groups的个数,后续的操作,将以相应的索引为单位(类似数组的下标,个数为数组的大小)。

get_group_name():获取指定group(由索引selector指定)的名称。

get_group_pins():获取指定group的所有pins(由索引selector指定),结果保存在pins(指针数组)和num_pins(指针)中。


(b)Pin configuration

  管脚有时可以被软件配置成多种方式,多数与它们作为输入/输出时的电气特性相关。例如,可以使一个输出管脚处于高阻状态,或是“三态”(意味着它被有效地断开连接)。你可以通过设置一个特定寄存器值将一个输入管脚与VDD或GND相连—上拉/下拉—以便在没有信号驱动管脚或是未连接时管脚上可以有个确定的值。体现在struct pinconf_ops数据结构中:

 41 pinconf_opsstruct pinconf_ops { 42 #ifdef CONFIG_GENERIC_PINCONF 43     bool is_generic; 44 #endif                     45     int (*pin_config_get) ();         48     int (*pin_config_set) ();          52     int (*pin_config_group_get) ();         55     int (*pin_config_group_set) ();          59     int (*pin_config_dbg_parse_modify) ();         62     void (*pin_config_dbg_show) ();               65     void (*pin_config_group_dbg_show) ();             68     void (*pin_config_config_dbg_show) ();          71 };

pin_config_get() : 获取指定pin(管脚的编号,由2.1中pin的注册信息获得)当前配置,保存在config指针中(配置的具体含义,只有pinctrl driver自己知道,下同)。

pin_config_set() : 设置指定pin的配置(可以同时配置多个config,具体意义要由相应pinctrl driver解释)。

pin_config_group_get()、pin_config_group_set() : 获取或者设置指定pin group的配置项。


(c)Pin multiplexing

  PINMUX也称作padmux,ballmux,它是由芯片厂商依据应用,使用一个特定的物理管脚(ball/pad/finger/等等)进行多种扩展复用,以支持不同功能的电气封装的习惯。芯片使用这个方法将不同的功能多路复用到不同管脚的范围。现在的SOC系统会包含几个I2C、SPI、SDIO/MMC等功能块,它们可以通过管脚多路复用设置被路由到不同的管脚。因为GPIO常常不足,通常会将所有当前未被使用的管脚用作GPIO。

  SoC中的很多管脚可以配置为不同的功能,pinctrl subsystem使用struct pinmux_ops来抽象pinmux有关的操作;

 63 struct pinmux_ops {   64     int (*request) (); 65     int (*free) (); 66     int (*get_functions_count) (); 67     const char *(*get_function_name) (); 69     int (*get_function_groups) (); 73     int (*set_mux) (); 75     int (*gpio_request_enable) (); 78     void (*gpio_disable_free) (); 81     int (*gpio_set_direction) (); 85     bool strict; 86 };

get_functions_count() : 获取系统中function的个数。

get_function_name() : 获取指定function的名称。

get_function_groups() : 获取指定function所占用的pin group(可以有多个)。

set_mux():将指定的pingroup(group_selector)设置为指定的function(func_selector)。

request() : 检查某个pin是否已作它用,用于管脚复用时的互斥(避免多个功能同时使用某个pin而不知道,导致奇怪的错误;


(2)如何使用

  当我们的driver去调用pinctrl系统接口来操作需要控制的pin脚,需要给出function selector以及function的pin group selector才能进行function mux的设定,function是pin脚功能如有的pin可以当作gpio也可以当作I2C的clk脚用。另外我们需要设定该pin的电气特性,会根据当前设备驱动的工作状态来调整pin的状态,为了方便管理pin control state,我们又提出了一个pin control state holder的概念,用来管理一个设备的所有的pin control状态,用struct pinctrl来表示:

 66 struct pinctrl { 67     struct list_head node;//系统中的所有device的pin control state holder被挂入到了一个全局链表中; 68     struct device *dev; //该pinctrl所属的device; 69     struct list_head states;//该设备的所有的状态被挂入到这个链表中; 70     struct pinctrl_state *state;//当前的pin control state; 71     struct list_head dt_maps;//从dts解析所有的state的链表; 72     struct kref users;//引用计数; 73 };

  通过struct pinctrl_state来表示当前设备的一组pin或者单个pin设置的状态;

 81 struct pinctrl_state { 82     struct list_head node;//链接下一个state; 83     const char *name; //该state的名字; 84     struct list_head settings;//属于该状态的所有的settings; 85 };

  一个pin state包含若干个setting,所有的settings被挂入一个链表中,链表头就是pin state中的settings成员:

120 struct pinctrl_setting {121     struct list_head node;122     enum pinctrl_map_type type;    123     struct pinctrl_dev *pctldev;   124     const char *dev_name;125     union {126         struct pinctrl_setting_mux mux;127         struct pinctrl_setting_configs configs;128     } data;129 };//pin mux相关的设定 92 struct pinctrl_setting_mux { 93     unsigned group;//该setting所对应的group selector; 94     unsigned func;//该setting所对应的function selector; 95 };105 struct pinctrl_setting_configs {106     unsigned group_or_pin;//该pin或者pin group的名字107     unsigned long *configs;//要设定的值的列表。这个值被用来写入HW;108     unsigned num_configs;//列表中值的个数;109 };

  当driver设定一个pin state的时候,pin control subsystem内部会遍历该state的settings链表,将一个一个的setting进行设定。这些settings有各种类型:

 19 enum pinctrl_map_type { 20     PIN_MAP_TYPE_INVALID, 21     PIN_MAP_TYPE_DUMMY_STATE, 22     PIN_MAP_TYPE_MUX_GROUP,//功能复用的setting; 23     PIN_MAP_TYPE_CONFIGS_PIN,//设定一个单pin的电气特性; 24     PIN_MAP_TYPE_CONFIGS_GROUP,//设定单pin group的电气特性; 25 };

  下面是pinctrl各个结构体的关系:

这里写图片描述


(二) pinctrl操作流程


(1)pinctrl初始化

  通过pinctrl_register()注册pingctrl驱动,传入已经定义好的pinctrl_desc,并实现pctlops,pmxops,confops这几个跟平台相关的函数集,通过操作soc相关的寄存器内容来完成pin相关的操作,以高通的msm_pinctrl_desc为例:

 398 static struct pinctrl_desc msm_pinctrl_desc = { 399     .pctlops = &msm_pinctrl_ops,    400     .pmxops = &msm_pinmux_ops, 401     .confops = &msm_pinconf_ops,    402     .owner = THIS_MODULE, 403 };
//kernel-3.18/drivers/pinctrl/core.c1734 struct pinctrl_dev *pinctrl_register(struct pinctrl_desc *pctldesc,1735                     struct device *dev, void *driver_data)1736 {1737     struct pinctrl_dev *pctldev;//pctldev就是软件上pinctrl的抽象;1738     int ret;         //分配pctldev数据结构,初始化后并添加到全局链表pinctrldev_list中;1745     pctldev = kzalloc(sizeof(*pctldev), GFP_KERNEL);1755     INIT_RADIX_TREE(&pctldev->pin_desc_tree, GFP_KERNEL); //pin_desc_tree用于存放所有的pin信息,由后面即将分析的pinctrl_register_pins来填充;//所有pin信息来源于输入参数pctldesc,也就是说每个pinctrl chip driver的实现者需要告诉pinctrl子系统该pinctrl chip所有的pin信息;1756     INIT_LIST_HEAD(&pctldev->gpio_ranges);1757     pctldev->dev = dev;1758     mutex_init(&pctldev->mutex);1759 1760     /* check core ops for sanity */1761     ret = pinctrl_check_ops(pctldev);1767     /* If we're implementing pinmuxing, check the ops for sanity */1768     if (pctldesc->pmxops) {1769         ret = pinmux_check_ops(pctldev);//如果提供了pinmux ops,检查下是否合法;1772     }1773     //同上;1774     /* If we're implementing pinconfig, check the ops for sanity */1775     if (pctldesc->confops) {1776         ret = pinconf_check_ops(pctldev);1779     }1780 1781     /* Register all the pins */1783     ret = pinctrl_register_pins(pctldev, pctldesc->pins, pctldesc->npins); //根据pctldesc里的pin信息注册所有的pin信息到pctldev里的pin_desc_tree管理起来;1790 1791     mutex_lock(&pinctrldev_list_mutex);1792     list_add_tail(&pctldev->node, &pinctrldev_list);  //将pctldev加入到全局链表;1794 1795     pctldev->p = pinctrl_get(pctldev->dev);1796 1797     if (!IS_ERR(pctldev->p)) {1798         pctldev->hog_default = //如果pinctrl设备提供了default状态,设置为default状态;1799             pinctrl_lookup_state(pctldev->p, PINCTRL_STATE_DEFAULT);1800         if (IS_ERR(pctldev->hog_default)) {1801             dev_dbg(dev, "failed to lookup the default state\n");1802         } else {1803             if (pinctrl_select_state(pctldev->p,1804                         pctldev->hog_default))1805                 dev_err(dev,1806                     "failed to select default state\n");1807         }1808 1809         pctldev->hog_sleep =1810             pinctrl_lookup_state(pctldev->p,1811                             PINCTRL_STATE_SLEEP);1812         if (IS_ERR(pctldev->hog_sleep))1813             dev_dbg(dev, "failed to lookup the sleep state\n");1814     }1815 1816     pinctrl_init_device_debugfs(pctldev);1817 1818     return pctldev;1824 }

  高通平台通过PINCTRL_PIN来定义了所有的pin脚num,name信息并放入到struct pinctrl_desc里面;

 265 static int pinctrl_register_pins(struct pinctrl_dev *pctldev, 266                  struct pinctrl_pin_desc const *pins, 267                  unsigned num_descs) 268 {    269     unsigned i; 270     int ret = 0; 271      272     for (i = 0; i < num_descs; i++) { //遍历传入的所有pin的数据结构,一个个处理它们;pinctrl driver会传入所有的pin管脚及对应的名称; 274         ret = pinctrl_register_one_pin(pctldev,                 pins[i].number, pins[i].name); 279     return 0; 280 } 
 227 static int pinctrl_register_one_pin(struct pinctrl_dev *pctldev, 228                     unsigned number, const char *name) 229 { 230     struct pin_desc *pindesc; 231  232     pindesc = pin_desc_get(pctldev, number); //radix_tree_lookup查看是否已经存在; 237  238     pindesc = kzalloc(sizeof(*pindesc), GFP_KERNEL);//分配一个pinctrl子系统用于管理pin的数据结构; 242     } 243  244     /* Set owner */ 245     pindesc->pctldev = pctldev;//指定该pin的拥有者; 246  247     /* Copy basic pin info */ 248     if (name) { 249         pindesc->name = name; 250     } else {//如果没有指定名字,用默认的格式组合一个; 251         pindesc->name = kasprintf(GFP_KERNEL, "PIN%u", number); 256         pindesc->dynamic_name = true; 257     } 258     //将该pin添加到pctldev->pin_desc_tree里管理起来 259     radix_tree_insert(&pctldev->pin_desc_tree, number, pindesc); 260     pr_debug("registered pin %d (%s) on %s\n", 261          number, pindesc->name, pctldev->desc->name); 262     return 0; 263 }

  这就清楚了,通过传入pinctrl_desc,里面包含了all pin的信息,注册pctldev,并不这些pin通过struct pin_desc来表示,并放到pctldev->pin_desc_tree的红黑树统一管理;


(2)获取pin control state holder


  现在来看看pinctrl_get() : 正如前面所说在设置pin 的state之前,我们需要先获取pin control state holder也就是pinctrl;可以通过devm_pinctrl_get()和pinctrl_get()来获取pinctrl,如果该dev之前没有创建pinctrl,都会调用到create_pinctrl()来创建一个holder;

 790 static struct pinctrl *create_pinctrl(struct device *dev) 791 { 792     struct pinctrl *p; 793     const char *devname; 794     struct pinctrl_maps *maps_node; 795     int i; 796     struct pinctrl_map const *map; 797     int ret; 798  804     p = kzalloc(sizeof(*p), GFP_KERNEL); //分配pin ctrl占用的内存并初始化;  805     if (p == NULL) { 806         dev_err(dev, "failed to alloc struct pinctrl\n"); 807         return ERR_PTR(-ENOMEM); 808     } 809     p->dev = dev; 810     INIT_LIST_HEAD(&p->states); 811     INIT_LIST_HEAD(&p->dt_maps);//这里的dt_maps就是用于存放所有的设置; 812  813     ret = pinctrl_dt_to_map(p);  //解析该设备的说有设备树信息,将解析的状态挂到states里,解析的设置挂到dt_maps当然,设置同时也挂到全局的maps里去了;// mapping table这个database的建立也是动态的,当第一次调用pin control state holder的get函数的时候,就会通过调用pinctrl_dt_to_map来建立该device需要的mapping entry。 818  819     devname = dev_name(dev); 820  821     mutex_lock(&pinctrl_maps_mutex); 822     /* Iterate over the pin control maps to locate the right ones */ 823     for_each_maps(maps_node, i, map) { //遍历所有的设置,这里遍历的是全局的maps链表,因为它要用到;    //pinctrl_map结构,而p->dt_maps里的不是该类型 824         /* Map must be for this device */ 825         if (strcmp(map->dev_name, devname)) 826             continue; 827  828         ret = add_setting(p, map);  //分析一个mapping entry,把这个setting的代码加入到holder中; 842         if (ret == -EPROBE_DEFER) { 843             pinctrl_free(p, false); 844             mutex_unlock(&pinctrl_maps_mutex); 845             return ERR_PTR(ret); 846         } 847     } 848     mutex_unlock(&pinctrl_maps_mutex); 849  855  856     kref_init(&p->users); 857     /* 把这个新增加的pin control state holder加入到全局链表中 */  858     /* Add the pinctrl handle to the global list */ 859     mutex_lock(&pinctrl_list_mutex); 860     list_add_tail(&p->node, &pinctrl_list); 861     mutex_unlock(&pinctrl_list_mutex); 862  863     return p; 864 }

  通过create_pinctrl()函数来创建一个pinctrl,通过pinctrl_dt_to_map()来解析,解析过程如下:

  1. 获取该pinctrl的device_node;
  2. 循环通过of_find_property()获取pinctrl-x,如下面的pinctrl-0,pinctrl-1;并of_property_read_string_index()获取pinctrl-names;
  3. 这里有根据pinctrl-names有两个state,例如:pinctrl-0 所包含的内容为一组pin的状态(pin configure)对应”cam_default”,cam_sensor_mclk0_default为其中的一个sub node,然后来解析这个sub node;最后调用pctldev->desc->pctlops->dt_node_to_map来解析这些pin configuration,具体解析方法跟平台有关系,定义在pinctrl_desc的pctlops,以struct pinctrl_map来表示;
 68 struct pinctrl_map { 69     const char *dev_name;//使用这个mapping entry的设备名; 70     const char *name;//该名字表示了该mapping entry,跟pinctrl-name指定的名字一致; 71     enum pinctrl_map_type type;//mapping type; 72     const char *ctrl_dev_name;pin controller这个设备的名字; 73     union { 74         struct pinctrl_map_mux mux; //mux 设置 75         struct pinctrl_map_configs configs;//config设置; 76     } data; 77 };
  1. 最后add_setting()通过把解析出来的map与state绑定,并把该pin configuration node的mapping entry信息注册到pinctrl系统中;
//以高通的dts为例:15     tlmm: pinctrl@1000000 {16         compatible = "qcom,msm8937-pinctrl";17         reg = <0x1000000 0x300000>;18         interrupts = <0 208 0>;19         gpio-controller;20         #gpio-cells = <2>;21         interrupt-controller;22         #interrupt-cells = <2>; 77 cam_sensor_mclk0_default: cam_sensor_mclk0_default { 78     /* MCLK0 */ 79     mux { 80         /* CLK, DATA */ 81         pins = "gpio26"; 82         function = "cam_mclk"; 83     }; 84  85     config { 86         pins = "gpio26"; 87         bias-disable; /* No PULL */ 88         drive-strength = <2>; /* 2 MA */ 89     }; 90 };171         pinctrl-names = "cam_default", "cam_suspend";172         pinctrl-0 = <&cam_sensor_mclk0_default173                 &cam_sensor_rear_default174                 &cam_sensor_rear_vdig>;175         pinctrl-1 = <&cam_sensor_mclk0_sleep &cam_sensor_rear_sleep176                 &cam_sensor_rear_vdig_sleep>;

  通过通过device tree来建立pin mapping database ,pinctrl driver确定了pin map各个字段的格式之后,就可以在dts文件中维护pin state以及相应的mapping table。pinctrl core在初始化的时候,会读取并解析dts,并生成pin map。在设备驱动的相应的位置,调用pinctrl subsystem提供的API,active或者deactive这些state。

  另外我们还需要设置device在初始化匹配驱动给它设置默认状态,这份工作就放在了设备模型里面来做:

static int really_probe(struct device *dev, struct device_driver *drv){    ……    ret = pinctrl_bind_pins(dev); //对该device涉及的pin进行pin control相关设定;}

  匹配驱动成功后调用驱动probe之前会执行pinctrl_bind_pins(): 这个函数也调用了devm_pinctrl_get来获取pinctrl并初始化该dev相关的pin设定为defaut状态;



(3)设置pin state


  在设置pincontrol state之前,先需要通过pinctrl_lookup_state()找到指定状态下的状态句柄,这个只是检测是否存在这个state:

 959 struct pinctrl_state *pinctrl_lookup_state(struct pinctrl *p, 960                          const char *name)               961 {  962     struct pinctrl_state *state;    963     //遍历pinctrl的state链表,找出名字匹配的state964     state = find_state(p, name);    965     if (!state) {         966         if (pinctrl_dummy_state) {//没有会创建一个空的state967             /* create dummy state */        969                 name);    970             state = create_state(p, name);  971         } else 972             state = ERR_PTR(-ENODEV);       973     } 974    975     return state; 976 }

  通过pinctrl_select_state()设定一个具体的pin control state接口。

 986 int pinctrl_select_state(struct pinctrl *p, struct pinctrl_state *state) 987 { 988     struct pinctrl_setting *setting, *setting2; 989     struct pinctrl_state *old_state = p->state; 990     int ret; 991  992     if (p->state == state) 993         return 0;  //如果当前就是该状态,直接返回成功 994  995     if (p->state) {1002         list_for_each_entry(setting, &p->state->settings, node) {1003             if (setting->type != PIN_MAP_TYPE_MUX_GROUP)1004                 continue;1005             pinmux_disable_setting(setting);1006         }1007     }1008 1009     p->state = NULL;1010 1011     /* Apply all the settings for the new state */1012     list_for_each_entry(setting, &state->settings, node) {//遍历该设备的该状态下的所有设置,一个个设置上去;1013         switch (setting->type) {1014         case PIN_MAP_TYPE_MUX_GROUP:1015             ret = pinmux_enable_setting(setting);//如果该设置是mux设置,那么调用pinmux_enable_setting,这里面就用到了前面填充的信息;1016             break;1017         case PIN_MAP_TYPE_CONFIGS_PIN:1018         case PIN_MAP_TYPE_CONFIGS_GROUP:1019             ret = pinconf_apply_setting(setting);//如果该设置是conf设置,那么调用pinconf_apply_setting,这里面就用到了前面填充的信息;1020             break;1021         default:1022             ret = -EINVAL;1023             break;1024         }1030 1031     p->state = state;//更新state1032 1033     return 0;

  最后我们来看看pinmux_enable_setting()是怎么设置的:

389 int pinmux_enable_setting(struct pinctrl_setting const *setting)390 {391     struct pinctrl_dev *pctldev = setting->pctldev;392     const struct pinctrl_ops *pctlops = pctldev->desc->pctlops;393     const struct pinmux_ops *ops = pctldev->desc->pmxops;394     int ret = 0;395     const unsigned *pins = NULL;396     unsigned num_pins = 0;397     int i;398     struct pin_desc *desc;399     //先获取这这个state的的pin group;400     if (pctlops->get_group_pins)401         ret = pctlops->get_group_pins(pctldev, setting->data.mux.group,402                           &pins, &num_pins);403 404     if (ret) {405         const char *gname;406 407         /* errors only affect debug data, so just warn */408         gname = pctlops->get_group_name(pctldev,409                         setting->data.mux.group);410         dev_warn(pctldev->dev,411              "could not get pins for group %s\n",412              gname);413         num_pins = 0;414     }415     //调用pin_request对该grop的所有pin417     for (i = 0; i < num_pins; i++) {418         ret = pin_request(pctldev, pins[i], setting->dev_name, NULL);//调用pinmuxops->request的来完成;434     }435 436     /* Now that we have acquired the pins, encode the mux setting *///在pctldev->ridx_tree查找注册的pin;437     for (i = 0; i < num_pins; i++) {438         desc = pin_desc_get(pctldev, pins[i]);445         desc->mux_setting = &(setting->data.mux);446     }447 448     ret = ops->set_mux(pctldev, setting->data.mux.func,449                setting->data.mux.group);

  这个函数主要完成两步操作,先request该group的每一个pin,然后传入func和group来set_mux,高通平台定义如下,传入一个group号给到set_mux,通过group设置相应的寄存器即可,不需要太多的探讨;

 176 static const struct pinmux_ops msm_pinmux_ops = { 177     .get_functions_count    = msm_get_functions_count, 178     .get_function_name  = msm_get_function_name, 179     .get_function_groups    = msm_get_function_groups, 180     .set_mux        = msm_pinmux_set_mux, 181 };
原创粉丝点击