【Linux基礎系列之】pinctrl系統

  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_PINMUX
153     unsigned mux_usecount;
154     const char *mux_owner;
155     const struct pinctrl_setting_mux *mux_setting;
156     const char *gpio_owner;
157 #endif
158 };

  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.c

1734 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_default
173                 &cam_sensor_rear_default
174                 &cam_sensor_rear_vdig>;
175         pinctrl-1 = <&cam_sensor_mclk0_sleep &cam_sensor_rear_sleep
176                 &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;//更新state
1032 
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的所有pin
417     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 };
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章