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()來解析,解析過程如下:
- 獲取該pinctrl的device_node;
- 循環通過of_find_property()獲取pinctrl-x,如下面的pinctrl-0,pinctrl-1;並of_property_read_string_index()獲取pinctrl-names;
- 這裏有根據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 };
- 最後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鏈表,找出名字匹配的state;
964 state = find_state(p, name);
965 if (!state) {
966 if (pinctrl_dummy_state) {//沒有會創建一個空的state;
967 /* 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 };