Pinctrl子系统
1.什么是Pinctrl子系统
Pinctrl: Pin Controller,引脚控制器,用来控制引脚的多路复用和配置参数的硬件模块,对于复用来说,一个引脚可能有多个功能,如GPIO,I2C,SPI等等,我们要想使用哪个功能就得去配置,对于配置参数如上拉,下拉,开漏,推挽等等,这里说是一个硬件模块,但是大多数SOC并没有这个模块,所以linux内核就在软件层抽象出了一个pinctrl子系统用来实现这个功能。下面是一个结构简图:
所以一个pinctrl子系统应当由以下三部分:
- 引脚枚举与命名(用来描述引脚,对所有引脚进行编号,命名,对引脚支持的功能进行描述)
- 引脚复用,复用为GPIO,I2C等功能
- 引脚配置,对引脚的的上拉、下拉、推挽、开漏、驱动能力进行配置
2.Pinctrl子系统的使用
Pinctrl子系统一般由芯片原厂的BSP工程时编写,所以我们主要是学会如何使用。
现在的驱动都是与设备树结合使用,所以一般我们使用Pinctrl子系统时主要体现在设备树中,在驱动程序中一般不用写Pinctrl相关的代码。下面采用一个案例来说明如何使用。
这是STM32MP157芯片串口3的设备节点
&usart3 {
pinctrl-names = "default", "sleep";
pinctrl-0 = <&usart3_pins_c>;
pinctrl-1 = <&usart3_sleep_pins_c>;
status = "okay";
};
- pinctrl-names:里边有两个字符串,这两个字符串是用来描述设备状态的,default:默认状态,sleep:休眠状态
- pinctrl-0 :pinctrl-names所描述的第一个设备状态default所对应的引脚节点
- pinctrl-1 :pinctrl-names所描述的第二个设备状态sleep所对应的引脚节点
如果有其他状态则继续添加,在pinctrl-names添加第三项,对应的引脚节点就是pinctrl-2。
上面所说的pinctrl-0和pinctrl-1的值 <&usart3_pins_c>、 <&usart3_sleep_pins_c>就是pincontroller子节点,最终pinctrl子系统会根据这个节点来配置引脚功能。这两个节点的定义如下图所示:
pin-controller{
usart3_pins_c: uart3-0 {
pins1 {
pinmux = <STM32_PINMUX('D', 8, AF7)>;
bias-disable;
drive-push-pull;
slew-rate = <0>;
};
pins2 {
pinmux = <STM32_PINMUX('D', 9, AF7)>;
bias-disable;
};
};
usart3_sleep_pins_c: uart3-sleep-0 {
pins {
pinmux = <STM32_PINMUX('D', 8, ANALOG)>,
<STM32_PINMUX('D', 9, ANALOG)>;
};
};
};
进过查STM32MP157数据手册:
usart3_pins_c节点:
usart3_sleep_pins_c节点:
通过上面代码及分析,我们可以将pinctrl子系统在设备树下的描述分为两部分:
- 客户端设备:
- pinctrl-names:描述设备状态
- pinctrl-n: n从0开始,用来描述每个设备状态下所使用引脚,该引脚在pin controller中定义
- pin-controller:
- 客户端设备节点下所使用的引脚复用功能和配置信息的描述。
我们再看以下imx6ul的设备树下对于pinctrl的使用:
客户端设备:
&uart2 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_uart2>;
uart-has-rtscts;
status = "okay";
};
pin-controller端:
iomuxc{
pinctrl_uart2: uart2grp {
fsl,pins = <
MX6UL_PAD_UART2_TX_DATA__UART2_DCE_TX 0x1b0b1
MX6UL_PAD_UART2_RX_DATA__UART2_DCE_RX 0x1b0b1
MX6UL_PAD_UART3_RX_DATA__UART2_DCE_RTS 0x1b0b1
MX6UL_PAD_UART3_TX_DATA__UART2_DCE_CTS 0x1b0b1
>;
};
};
我们可以通过Documentation/devicetree/bindings/pinctrl/fsl,imx-pinctrl.txt文档得知:
- MX6UL_PAD_UART2_TX_DATA__UART2_DCE_TX这种类型为一个宏定义,里边有5个值,用来配置引脚的复用功能,复用为串口2的TX功能。
- 0x1b0b1:配置信息,配置上下拉、驱动能力等等
通过对比上面STM32MP157的设备树和imx6ul的设备树信息可知:
客户端设备:统一的格式,都是通过pinctrl-names描述设备状态,pinctrl-n用来指定对于客户端每个状态下对应的引脚。
pin-controller:没有统一的格式,对于不同的SOC厂家的格式不同,但是最后要实现的目的都是一致的,都是要设置引脚复用和引脚配置
3.Pinctrl子系统相关数据结构
以STM32MP157为例分析来分析Pinctrl子系统:位于drivers/pinctrl/stm32/pinctrl-stm32mp157.c文件
pinctrl: pin-controller@50002000 {
#address-cells = <1>;
#size-cells = <1>;
compatible = "st,stm32mp157-pinctrl";
ranges = <0 0x50002000 0xa400>;
interrupt-parent = <&exti>;
st,syscfg = <&exti 0x60 0xff>;
hwlocks = <&hsem 0 1>;
pins-are-numbered;
相应的可以找到它的驱动代码:位于drivers/pinctrl/stm32/pinctrl-stm32mp157.c
static const struct of_device_id stm32mp157_pctrl_match[] = {
{
.compatible = "st,stm32mp157-pinctrl",
.data = &stm32mp157_match_data,
},
{
.compatible = "st,stm32mp157-z-pinctrl",
.data = &stm32mp157_z_match_data,
},
{ }
};
static struct platform_driver stm32mp157_pinctrl_driver = {
.probe = stm32_pctl_probe,
.driver = {
.name = "stm32mp157-pinctrl",
.of_match_table = stm32mp157_pctrl_match,
.pm = &stm32_pinctrl_dev_pm_ops,
},
};
在驱动和设备匹配成功后,调用stm32_pctl_probe函数:位于drivers/pinctrl/stm32/pinctrl-stm32.c文件
struct stm32_pinctrl {
struct device *dev;
struct pinctrl_dev *pctl_dev;
struct pinctrl_desc pctl_desc;
struct stm32_pinctrl_group *groups;
unsigned ngroups;
const char **grp_names;
struct stm32_gpio_bank *banks;
unsigned nbanks;
const struct stm32_pinctrl_match_data *match_data;
struct irq_domain *domain;
struct regmap *regmap;
struct regmap_field *irqmux[STM32_GPIO_PINS_PER_BANK];
struct hwspinlock *hwlock;
struct stm32_desc_pin *pins;
u32 npins;
u32 pkg;
u16 irqmux_map;
spinlock_t irqmux_lock;
u32 pin_base_shift;
};
int stm32_pctl_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
struct device_node *child;
const struct of_device_id *match;
struct device *dev = &pdev->dev;
struct stm32_pinctrl *pctl;
struct pinctrl_pin_desc *pins;
int i, ret, hwlock_id, banks = 0;
if (!np)
return -EINVAL;
match = of_match_device(dev->driver->of_match_table, dev);
if (!match || !match->data)
return -EINVAL;
if (!of_find_property(np, "pins-are-numbered", NULL)) {
dev_err(dev, "only support pins-are-numbered format\n");
return -EINVAL;
}
pctl = devm_kzalloc(dev, sizeof(*pctl), GFP_KERNEL);
if (!pctl)
return -ENOMEM;
platform_set_drvdata(pdev, pctl);
pctl->domain = stm32_pctrl_get_irq_domain(np);
if (IS_ERR(pctl->domain))
return PTR_ERR(pctl->domain);
hwlock_id = of_hwspin_lock_get_id(pdev->dev.of_node, 0);
if (hwlock_id < 0) {
if (hwlock_id == -EPROBE_DEFER)
return hwlock_id;
} else {
pctl->hwlock = hwspin_lock_request_specific(hwlock_id);
}
spin_lock_init(&pctl->irqmux_lock);
pctl->dev = dev;
pctl->match_data = match->data;
stm32_pctl_get_package(np, pctl);
pctl->pins = devm_kcalloc(pctl->dev, pctl->match_data->npins,
sizeof(*pctl->pins), GFP_KERNEL);
if (!pctl->pins)
return -ENOMEM;
ret = stm32_pctrl_create_pins_tab(pctl, pctl->pins);
if (ret)
return ret;
ret = stm32_pctrl_build_state(pdev);
if (ret) {
dev_err(dev, "build state failed: %d\n", ret);
return -EINVAL;
}
if (pctl->domain) {
ret = stm32_pctrl_dt_setup_irq(pdev, pctl);
if (ret)
return ret;
}
pins = devm_kcalloc(&pdev->dev, pctl->npins, sizeof(*pins),
GFP_KERNEL);
if (!pins)
return -ENOMEM;
for (i = 0; i < pctl->npins; i++)
pins[i] = pctl->pins[i].pin;
pctl->pctl_desc.name = dev_name(&pdev->dev);
pctl->pctl_desc.owner = THIS_MODULE;
pctl->pctl_desc.pins = pins;
pctl->pctl_desc.npins = pctl->npins;
pctl->pctl_desc.link_consumers = true;
pctl->pctl_desc.confops = &stm32_pconf_ops;
pctl->pctl_desc.pctlops = &stm32_pctrl_ops;
pctl->pctl_desc.pmxops = &stm32_pmx_ops;
pctl->dev = &pdev->dev;
pctl->pin_base_shift = pctl->match_data->pin_base_shift;
pctl->pctl_dev = devm_pinctrl_register(&pdev->dev, &pctl->pctl_desc,
pctl);
if (IS_ERR(pctl->pctl_dev)) {
dev_err(&pdev->dev, "Failed pinctrl registration\n");
return PTR_ERR(pctl->pctl_dev);
}
for_each_available_child_of_node(np, child)
if (of_property_read_bool(child, "gpio-controller"))
banks++;
if (!banks) {
dev_err(dev, "at least one GPIO bank is required\n");
return -EINVAL;
}
pctl->banks = devm_kcalloc(dev, banks, sizeof(*pctl->banks),
GFP_KERNEL);
if (!pctl->banks)
return -ENOMEM;
i = 0;
for_each_available_child_of_node(np, child) {
struct stm32_gpio_bank *bank = &pctl->banks[i];
if (of_property_read_bool(child, "gpio-controller")) {
bank->rstc = of_reset_control_get_exclusive(child,
NULL);
if (PTR_ERR(bank->rstc) == -EPROBE_DEFER)
return -EPROBE_DEFER;
bank->clk = of_clk_get_by_name(child, NULL);
if (IS_ERR(bank->clk)) {
if (PTR_ERR(bank->clk) != -EPROBE_DEFER)
dev_err(dev,
"failed to get clk (%ld)\n",
PTR_ERR(bank->clk));
return PTR_ERR(bank->clk);
}
i++;
}
}
for_each_available_child_of_node(np, child) {
if (of_property_read_bool(child, "gpio-controller")) {
ret = stm32_gpiolib_register_bank(pctl, child);
if (ret) {
of_node_put(child);
return ret;
}
pctl->nbanks++;
}
}
dev_info(dev, "Pinctrl STM32 initialized\n");
return 0;
}
与Pinctrl相关的主要如下:
pctl->pctl_desc.name = dev_name(&pdev->dev);
pctl->pctl_desc.owner = THIS_MODULE;
pctl->pctl_desc.pins = pins;
pctl->pctl_desc.npins = pctl->npins;
pctl->pctl_desc.link_consumers = true;
pctl->pctl_desc.confops = &stm32_pconf_ops;
pctl->pctl_desc.pctlops = &stm32_pctrl_ops;
pctl->pctl_desc.pmxops = &stm32_pmx_ops;
pctl->dev = &pdev->dev;
pctl->pin_base_shift = pctl->match_data->pin_base_shift;
pctl->pctl_dev = devm_pinctrl_register(&pdev->dev, &pctl->pctl_desc,
pctl);
pctl->pctl_desc是一个struct pinctrl_desc类型的结构体,从字面意思可看出就是pinctrl describe,用来描述pinctrl,最后通过struct pinctrl_dev *devm_pinctrl_register(struct device *dev, struct pinctrl_desc *pctldesc,void *driver_data)注册struct pinctrl_desc结构体,生成struct pinctrl_dev结构体,也就是pinctrl设备。pinctrl_dev结构体如下,可见每一个pinctrl设备中都有一个struct pinctrl_desc结构体
struct pinctrl_dev {
struct list_head node;
struct pinctrl_desc *desc;
struct radix_tree_root pin_desc_tree;
#ifdef CONFIG_GENERIC_PINCTRL_GROUPS
struct radix_tree_root pin_group_tree;
unsigned int num_groups;
#endif
#ifdef CONFIG_GENERIC_PINMUX_FUNCTIONS
struct radix_tree_root pin_function_tree;
unsigned int num_functions;
#endif
struct list_head gpio_ranges;
struct device *dev;
struct module *owner;
void *driver_data;
struct pinctrl *p;
struct pinctrl_state *hog_default;
struct pinctrl_state *hog_sleep;
struct mutex mutex;
#ifdef CONFIG_DEBUG_FS
struct dentry *device_root;
#endif
};
从上面的代码可以看出,在写一个pinctrl驱动时我们要做的主要是:
- 分配struct pinctrl_desc结构体
- 设置struct pinctrl_desc结构体
- 注册struct pinctrl_desc结构体
所以我们重点分析struct pinctrl_desc结构体:位于include/linux/pinctrl/pinctrl.h文件
struct pinctrl_desc {
const char *name;
const struct pinctrl_pin_desc *pins;
unsigned int npins;
const struct pinctrl_ops *pctlops;
const struct pinmux_ops *pmxops;
const struct pinconf_ops *confops;
struct module *owner;
#ifdef CONFIG_GENERIC_PINCONF
unsigned int num_custom_params;
const struct pinconf_generic_params *custom_params;
const struct pin_config_item *custom_conf_items;
#endif
bool link_consumers;
};
从上述结构体struct pinctrl_desc 结构体可以看出它包含了我们前面分析的三点:
- 引脚枚举与命名:const struct pinctrl_pin_desc *pins;
- 引脚复用:const struct pinmux_ops *pmxops;
- 引脚配置:const struct pinconf_ops *confops;
全局引脚控制const struct pinctrl_ops结构体:位于include/linux/pinctrl/pinctrl.h文件
struct pinctrl_ops {
int (*get_groups_count) (struct pinctrl_dev *pctldev);
const char *(*get_group_name) (struct pinctrl_dev *pctldev,
unsigned selector);
int (*get_group_pins) (struct pinctrl_dev *pctldev,
unsigned selector,
const unsigned **pins,
unsigned *num_pins);
void (*pin_dbg_show) (struct pinctrl_dev *pctldev, struct seq_file *s,
unsigned offset);
int (*dt_node_to_map) (struct pinctrl_dev *pctldev,
struct device_node *np_config,
struct pinctrl_map **map, unsigned *num_maps);
void (*dt_free_map) (struct pinctrl_dev *pctldev,
struct pinctrl_map *map, unsigned num_maps);
};
引脚复用:const struct pinmux_ops 位于include/linux/pinctrl/pinmux.h文件
struct pinmux_ops {
int (*request) (struct pinctrl_dev *pctldev, unsigned offset);
int (*free) (struct pinctrl_dev *pctldev, unsigned offset);
int (*get_functions_count) (struct pinctrl_dev *pctldev);
const char *(*get_function_name) (struct pinctrl_dev *pctldev,
unsigned selector);
int (*get_function_groups) (struct pinctrl_dev *pctldev,
unsigned selector,
const char * const **groups,
unsigned *num_groups);
int (*set_mux) (struct pinctrl_dev *pctldev, unsigned func_selector,
unsigned group_selector);
int (*gpio_request_enable) (struct pinctrl_dev *pctldev,
struct pinctrl_gpio_range *range,
unsigned offset);
void (*gpio_disable_free) (struct pinctrl_dev *pctldev,
struct pinctrl_gpio_range *range,
unsigned offset);
int (*gpio_set_direction) (struct pinctrl_dev *pctldev,
struct pinctrl_gpio_range *range,
unsigned offset,
bool input);
bool strict;
};
引脚配置:const struct pinconf_ops 位于include/linux/pinctrl/pinconf.h文件
struct pinconf_ops {
#ifdef CONFIG_GENERIC_PINCONF
bool is_generic;
#endif
int (*pin_config_get) (struct pinctrl_dev *pctldev,
unsigned pin,
unsigned long *config);
int (*pin_config_set) (struct pinctrl_dev *pctldev,
unsigned pin,
unsigned long *configs,
unsigned num_configs);
int (*pin_config_group_get) (struct pinctrl_dev *pctldev,
unsigned selector,
unsigned long *config);
int (*pin_config_group_set) (struct pinctrl_dev *pctldev,
unsigned selector,
unsigned long *configs,
unsigned num_configs);
void (*pin_config_dbg_show) (struct pinctrl_dev *pctldev,
struct seq_file *s,
unsigned offset);
void (*pin_config_group_dbg_show) (struct pinctrl_dev *pctldev,
struct seq_file *s,
unsigned selector);
void (*pin_config_config_dbg_show) (struct pinctrl_dev *pctldev,
struct seq_file *s,
unsigned long config);
};
从设备树中对节点进行设定后pinctrl子系统是如何一步一步将引脚的复用功能和配置信息提取,最后对硬件寄存器进行操作实现引脚的控制呢,主要过程如下:
首先当设备树节点与驱动匹配成功后首先会调用drivers/base/dd.c中的static int really_probe(struct device *dev, struct device_driver *drv)函数,在该函数中就实现了pinctrl子系统从设备树节点解析到最后对引脚进行复用功能设置,以及上下拉等配置。具体的代码量太大,我将实现过程列了出来,可以对比下面的函数调用过程去分析。
所以最终pinctrl子系统框架会调用在驱动中构建的struct pinctrl_desc结构体下的const struct pinctrl_ops、const struct pinmux_ops、const struct pinconf_ops中的操作函数对引脚进行配置。
我们可以看其中比较重要的几个结构体
struct device结构体下的struct dev_pin_info:
struct pinctrl {
struct list_head node;
struct device *dev;
struct list_head states;
struct pinctrl_state *state;
struct list_head dt_maps;
struct kref users;
};
struct pinctrl_state {
struct list_head node;
const char *name;
struct list_head settings;
};
struct dev_pin_info {
struct pinctrl *p;
struct pinctrl_state *default_state;
struct pinctrl_state *init_state;
#ifdef CONFIG_PM
struct pinctrl_state *sleep_state;
struct pinctrl_state *idle_state;
#endif
};
pinctrl相关结构体
struct pinctrl_dev {
struct list_head node;
struct pinctrl_desc *desc;
struct radix_tree_root pin_desc_tree;
#ifdef CONFIG_GENERIC_PINCTRL_GROUPS
struct radix_tree_root pin_group_tree;
unsigned int num_groups;
#endif
#ifdef CONFIG_GENERIC_PINMUX_FUNCTIONS
struct radix_tree_root pin_function_tree;
unsigned int num_functions;
#endif
struct list_head gpio_ranges;
struct device *dev;
struct module *owner;
void *driver_data;
struct pinctrl *p;
struct pinctrl_state *hog_default;
struct pinctrl_state *hog_sleep;
struct mutex mutex;
#ifdef CONFIG_DEBUG_FS
struct dentry *device_root;
#endif
};
&usart3 {
pinctrl-names = "default", "sleep";
pinctrl-0 = <&usart3_pins_c>;
pinctrl-1 = <&usart3_sleep_pins_c>;
status = "okay";
};
每个设备驱动下都有struct device,如I2c驱动或platform驱动,在它构建的结构体中都有struct device成员,struct device下就有一个和pinctrl相关的成员struct dev_pin_info,也就是该设备下的引脚描述,这个结构体有五个元素:
- struct pinctrl:如果设备节点pinctrl-names有描述状态,则最终会将每个状态解析为一个pinctrl,如上面的usart节点,在struct dev_pin_info下的struct pinctrl *p中就会解析出一个pinctrl table,里边有两个成员,第一个成员pinctrl的state就指向default状态struct pinctrl_state *default_state;第二个成员pinctrl的state就指向sleep状态struct pinctrl_state *sleep_state
- struct pinctrl_state *default_state: default状态,例如usart3节点中的default状态对应的是pinctrl-0 = <&usart3_pins_c>;最后会将usart3_pins_c这个引脚配置节点解析为一个struct pinctrl_state,里边包含了状态名称和该状态对应的一系类setting,最后就是根据这一系类setting来对引脚进行配置。其他的struct pinctrl_state与它类似,就是将设备树中状态所对应的引脚配置节点解析为一个struct pinctrl_state,里边存储状态和该状态对应的setting,setting结构体后面会讲解,其实设备树引脚配置节点首先是被解析成map tabel,最后将map table转化为setting table。
map相关的结构体
struct pinctrl_maps {
struct list_head node;
const struct pinctrl_map *maps;
unsigned num_maps;
};
enum pinctrl_map_type {
PIN_MAP_TYPE_INVALID,
PIN_MAP_TYPE_DUMMY_STATE,
PIN_MAP_TYPE_MUX_GROUP,
PIN_MAP_TYPE_CONFIGS_PIN,
PIN_MAP_TYPE_CONFIGS_GROUP,
};
struct pinctrl_map_mux {
const char *group;
const char *function;
};
struct pinctrl_map_configs {
const char *group_or_pin;
unsigned long *configs;
unsigned num_configs;
};
struct pinctrl_map {
const char *dev_name;
const char *name;
enum pinctrl_map_type type;
const char *ctrl_dev_name;
union {
struct pinctrl_map_mux mux;
struct pinctrl_map_configs configs;
} data;
};
map是从设备树解析而来,我们可以看出,每个map都有类型,一般常见的就是mux类型和configs类型。 struct pinctrl_map_mux mux和struct pinctrl_map_configs configs是一个联合体,当map类型为mux是就使用struct pinctrl_map_mux mux;当map类型为configs是就使用struct pinctrl_map_configs configs;
- mux类型:
- PIN_MAP_TYPE_MUX_GROUP:用来引脚复用功能的配置
- 对于mux类型,使用struct pinctrl_map_mux mux来描述这个map功能,这个结构体有两项,第一项group用来描述组名称,第二个参数function用来描述组功能,这个参数不同的soc厂商对它的定义则不同,像STM32MP157就是用"gpio",“af0”,"af1"等来描述
- configs类型:
- PIN_MAP_TYPE_CONFIGS_PIN:对单个引脚进行上下拉、驱动能力等配置
- 对于configs_pin类型,使用 pinctrl_map_configs configs来描述这个map功能,这个结构体有三项,第一项group_or_pin用来描述单个引脚名称,第二个参数*configs是配置的参数列表,第三个参数num_configs为配置参数的总数。配置参数对于不同的soc厂商对于configs的定义不同
- PIN_MAP_TYPE_CONFIGS_GROUP:对一组引脚进行上下拉等配置
- 对于configs_group类型,使用 pinctrl_map_configs configs来描述这个map功能,这个结构体有三项,第一项group_or_pin用来描述组名称,第二个参数*configs是配置的参数列表,第三个参数num_configs为配置参数的总数。配置参数对于不同的soc厂商对于configs的定义不同
struct pinctrl_maps 结构体就是将单个map构建成的链表,解析出来的map最后会通过struct pinctrl_maps链接成map table.
enum pinctrl_map_type {
PIN_MAP_TYPE_INVALID,
PIN_MAP_TYPE_DUMMY_STATE,
PIN_MAP_TYPE_MUX_GROUP,
PIN_MAP_TYPE_CONFIGS_PIN,
PIN_MAP_TYPE_CONFIGS_GROUP,
};
struct pinctrl_setting_mux {
unsigned group;
unsigned func;
};
struct pinctrl_setting_configs {
unsigned group_or_pin;
unsigned long *configs;
unsigned num_configs;
};
struct pinctrl_setting {
struct list_head node;
enum pinctrl_map_type type;
struct pinctrl_dev *pctldev;
const char *dev_name;
union {
struct pinctrl_setting_mux mux;
struct pinctrl_setting_configs configs;
} data;
};
从struct pinctrl_setting 和struct pinctrl_map相比较,可以看出它很相似,这也是通过前面所说的驱动文件中注册的的struct pinctrl_desc 下的const struct pinmux_ops *pmxops和const struct pinconf_ops *confops中所定义的相关操作获取map table各个map的参数值赋值给setting中相关的参数。最后调用这些操作函数中的相关设置函数使用setting对引脚进行复用功能和上拉,下拉,驱动能力等的配置。
4.STM32MP157 的Pincontroller实现过程
-
设备树 pinctrl: pin-controller@50002000 {
#address-cells = <1>;
#size-cells = <1>;
compatible = "st,stm32mp157-pinctrl";
ranges = <0 0x50002000 0xa400>;
interrupt-parent = <&exti>;
st,syscfg = <&exti 0x60 0xff>;
hwlocks = <&hsem 0 1>;
pins-are-numbered;
}
驱动文件:位于drivers/pinctrl/stm32/pinctrl-stm32mp157.c static const struct stm32_desc_pin stm32mp157_pins[] = {
STM32_PIN_PKG(
PINCTRL_PIN(0, "PA0"),
STM32MP_PKG_AA | STM32MP_PKG_AC | STM32MP_PKG_AB | STM32MP_PKG_AD,
STM32_FUNCTION(0, "GPIOA0"),
STM32_FUNCTION(2, "TIM2_CH1 TIM2_ETR"),
STM32_FUNCTION(3, "TIM5_CH1"),
STM32_FUNCTION(4, "TIM8_ETR"),
STM32_FUNCTION(5, "TIM15_BKIN"),
STM32_FUNCTION(8, "USART2_CTS USART2_NSS"),
STM32_FUNCTION(9, "UART4_TX"),
STM32_FUNCTION(10, "SDMMC2_CMD"),
STM32_FUNCTION(11, "SAI2_SD_B"),
STM32_FUNCTION(12, "ETH1_GMII_CRS ETH1_MII_CRS"),
STM32_FUNCTION(16, "EVENTOUT"),
STM32_FUNCTION(17, "ANALOG")
),
STM32_PIN_PKG(
PINCTRL_PIN(1, "PA1"),
STM32MP_PKG_AA | STM32MP_PKG_AC | STM32MP_PKG_AB | STM32MP_PKG_AD,
STM32_FUNCTION(0, "GPIOA1"),
STM32_FUNCTION(1, "ETH_CLK"),
STM32_FUNCTION(2, "TIM2_CH2"),
STM32_FUNCTION(3, "TIM5_CH2"),
STM32_FUNCTION(4, "LPTIM3_OUT"),
STM32_FUNCTION(5, "TIM15_CH1N"),
STM32_FUNCTION(8, "USART2_RTS USART2_DE"),
STM32_FUNCTION(9, "UART4_RX"),
STM32_FUNCTION(10, "QUADSPI_BK1_IO3"),
STM32_FUNCTION(11, "SAI2_MCLK_B"),
STM32_FUNCTION(12, "ETH1_GMII_RX_CLK ETH1_MII_RX_CLK ETH1_RGMII_RX_CLK ETH1_RMII_REF_CLK"),
STM32_FUNCTION(15, "LCD_R2"),
STM32_FUNCTION(16, "EVENTOUT"),
STM32_FUNCTION(17, "ANALOG")
),
..........
};
static const struct stm32_desc_pin stm32mp157_z_pins[] = {
STM32_PIN_PKG(
PINCTRL_PIN(400, "PZ0"),
STM32MP_PKG_AA | STM32MP_PKG_AC,
STM32_FUNCTION(0, "GPIOZ0"),
STM32_FUNCTION(3, "I2C6_SCL"),
STM32_FUNCTION(4, "I2C2_SCL"),
STM32_FUNCTION(6, "SPI1_SCK I2S1_CK"),
STM32_FUNCTION(8, "USART1_CK"),
STM32_FUNCTION(9, "SPI6_SCK"),
STM32_FUNCTION(16, "EVENTOUT"),
STM32_FUNCTION(17, "ANALOG")
),
STM32_PIN_PKG(
PINCTRL_PIN(401, "PZ1"),
STM32MP_PKG_AA | STM32MP_PKG_AC,
STM32_FUNCTION(0, "GPIOZ1"),
STM32_FUNCTION(3, "I2C6_SDA"),
STM32_FUNCTION(4, "I2C2_SDA"),
STM32_FUNCTION(5, "I2C5_SDA"),
STM32_FUNCTION(6, "SPI1_MISO I2S1_SDI"),
STM32_FUNCTION(7, "I2C4_SDA"),
STM32_FUNCTION(8, "USART1_RX"),
STM32_FUNCTION(9, "SPI6_MISO"),
STM32_FUNCTION(16, "EVENTOUT"),
STM32_FUNCTION(17, "ANALOG")
),
.........
};
static struct stm32_pinctrl_match_data stm32mp157_match_data = {
.pins = stm32mp157_pins,
.npins = ARRAY_SIZE(stm32mp157_pins),
};
static struct stm32_pinctrl_match_data stm32mp157_z_match_data = {
.pins = stm32mp157_z_pins,
.npins = ARRAY_SIZE(stm32mp157_z_pins),
.pin_base_shift = STM32MP157_Z_BASE_SHIFT,
};
static const struct of_device_id stm32mp157_pctrl_match[] = {
{
.compatible = "st,stm32mp157-pinctrl",
.data = &stm32mp157_match_data,
},
{
.compatible = "st,stm32mp157-z-pinctrl",
.data = &stm32mp157_z_match_data,
},
{ }
};
static const struct dev_pm_ops stm32_pinctrl_dev_pm_ops = {
SET_LATE_SYSTEM_SLEEP_PM_OPS(NULL, stm32_pinctrl_resume)
};
static struct platform_driver stm32mp157_pinctrl_driver = {
.probe = stm32_pctl_probe,
.driver = {
.name = "stm32mp157-pinctrl",
.of_match_table = stm32mp157_pctrl_match,
.pm = &stm32_pinctrl_dev_pm_ops,
},
};
static int __init stm32mp157_pinctrl_init(void)
{
return platform_driver_register(&stm32mp157_pinctrl_driver);
}
arch_initcall(stm32mp157_pinctrl_init);
可以看出Pinctrl驱动为一个标准的platform驱动,驱动的probe函数在drivers/pinctrl/stm32/pinctrl-stm32.c文件中 int stm32_pctl_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
struct device_node *child;
const struct of_device_id *match;
struct device *dev = &pdev->dev;
struct stm32_pinctrl *pctl;
struct pinctrl_pin_desc *pins;
int i, ret, hwlock_id, banks = 0;
if (!np)
return -EINVAL;
match = of_match_device(dev->driver->of_match_table, dev);
if (!match || !match->data)
return -EINVAL;
if (!of_find_property(np, "pins-are-numbered", NULL)) {
dev_err(dev, "only support pins-are-numbered format\n");
return -EINVAL;
}
pctl = devm_kzalloc(dev, sizeof(*pctl), GFP_KERNEL);
if (!pctl)
return -ENOMEM;
platform_set_drvdata(pdev, pctl);
pctl->domain = stm32_pctrl_get_irq_domain(np);
if (IS_ERR(pctl->domain))
return PTR_ERR(pctl->domain);
hwlock_id = of_hwspin_lock_get_id(pdev->dev.of_node, 0);
if (hwlock_id < 0) {
if (hwlock_id == -EPROBE_DEFER)
return hwlock_id;
} else {
pctl->hwlock = hwspin_lock_request_specific(hwlock_id);
}
spin_lock_init(&pctl->irqmux_lock);
pctl->dev = dev;
pctl->match_data = match->data;
stm32_pctl_get_package(np, pctl);
pctl->pins = devm_kcalloc(pctl->dev, pctl->match_data->npins,
sizeof(*pctl->pins), GFP_KERNEL);
if (!pctl->pins)
return -ENOMEM;
ret = stm32_pctrl_create_pins_tab(pctl, pctl->pins);
if (ret)
return ret;
ret = stm32_pctrl_build_state(pdev);
if (ret) {
dev_err(dev, "build state failed: %d\n", ret);
return -EINVAL;
}
if (pctl->domain) {
ret = stm32_pctrl_dt_setup_irq(pdev, pctl);
if (ret)
return ret;
}
pins = devm_kcalloc(&pdev->dev, pctl->npins, sizeof(*pins),
GFP_KERNEL);
if (!pins)
return -ENOMEM;
for (i = 0; i < pctl->npins; i++)
pins[i] = pctl->pins[i].pin;
pctl->pctl_desc.name = dev_name(&pdev->dev);
pctl->pctl_desc.owner = THIS_MODULE;
pctl->pctl_desc.pins = pins;
pctl->pctl_desc.npins = pctl->npins;
pctl->pctl_desc.link_consumers = true;
pctl->pctl_desc.confops = &stm32_pconf_ops;
pctl->pctl_desc.pctlops = &stm32_pctrl_ops;
pctl->pctl_desc.pmxops = &stm32_pmx_ops;
pctl->dev = &pdev->dev;
pctl->pin_base_shift = pctl->match_data->pin_base_shift;
pctl->pctl_dev = devm_pinctrl_register(&pdev->dev, &pctl->pctl_desc,
pctl);
if (IS_ERR(pctl->pctl_dev)) {
dev_err(&pdev->dev, "Failed pinctrl registration\n");
return PTR_ERR(pctl->pctl_dev);
}
for_each_available_child_of_node(np, child)
if (of_property_read_bool(child, "gpio-controller"))
banks++;
if (!banks) {
dev_err(dev, "at least one GPIO bank is required\n");
return -EINVAL;
}
pctl->banks = devm_kcalloc(dev, banks, sizeof(*pctl->banks),
GFP_KERNEL);
if (!pctl->banks)
return -ENOMEM;
i = 0;
for_each_available_child_of_node(np, child) {
struct stm32_gpio_bank *bank = &pctl->banks[i];
if (of_property_read_bool(child, "gpio-controller")) {
bank->rstc = of_reset_control_get_exclusive(child,
NULL);
if (PTR_ERR(bank->rstc) == -EPROBE_DEFER)
return -EPROBE_DEFER;
bank->clk = of_clk_get_by_name(child, NULL);
if (IS_ERR(bank->clk)) {
if (PTR_ERR(bank->clk) != -EPROBE_DEFER)
dev_err(dev,
"failed to get clk (%ld)\n",
PTR_ERR(bank->clk));
return PTR_ERR(bank->clk);
}
i++;
}
}
for_each_available_child_of_node(np, child) {
if (of_property_read_bool(child, "gpio-controller")) {
ret = stm32_gpiolib_register_bank(pctl, child);
if (ret) {
of_node_put(child);
return ret;
}
pctl->nbanks++;
}
}
dev_info(dev, "Pinctrl STM32 initialized\n");
return 0;
}
里边所涉及的函数的功能注释了出来,其他的代码参考源码具体分析。
|