一、pinctrl与gpio子系统概述
1.1 gpio子系统
主要负责读/写引脚值、设置引脚为输入或输出模式、中断等基本操作。
1.2 pinctrl子系统
管理所有可控制的引脚,包括引脚的复用功能、电气特性等。
1.2.1 pinctrl子系统的主要功能包括
- 引脚复用:大多数引脚都可以通过配置寄存器来选择复用成不同的功能。
- 引脚配置:包括设置引脚的上拉/下拉电阻、速度、驱动能力等电气特性。
1.2.2与gpio子系统的关系
部分soc gpio驱动会调用pinctrl系统接口设置pin脚状态,gpio控制器下gpio-ranges属性会引用都pinctrl设备节点,同步gpio-ranges到pinctrl dev的gpio_ranges链表
二、pinctrl子系统
2.1 pinctrl节点设备树配置
rk:
pinctrl: pinctrl {
compatible = "rockchip,rk3568-pinctrl";
rockchip,grf = <&grf>;
rockchip,pmu = <&pmugrf>;
#address-cells = <2>;
#size-cells = <2>;
ranges;gpio0: gpio@fdd60000 {
compatible = "rockchip,gpio-bank";
reg = <0x0 0xfdd60000 0x0 0x100>;
interrupts = <GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&pmucru PCLK_GPIO0>, <&pmucru DBCLK_GPIO0>;gpio-controller;
#gpio-cells = <2>;
gpio-ranges = <&pinctrl 0 0 32>;
interrupt-controller;
#interrupt-cells = <2>;
};......
ti:
main_pmx0: pinctrl@11c000 {
compatible = "pinctrl-single";//通用pinctrl驱动
/* Proxy 0 addressing */
reg = <0x0 0x11c000 0x0 0x2b4>;
#pinctrl-cells = <1>;
pinctrl-single,register-width = <32>;
pinctrl-single,function-mask = <0xffffffff>;
};......
&main_pmx0 {
......gpio_main_pins_default: gpio-main-pins-default {
pinctrl-single,pins = <
J721E_IOPAD(0x18c, PIN_INPUT, 7) /* (V23) RGMII6_RX_CTL.GPIO0_98 */
J721E_IOPAD(0x1a4, PIN_INPUT, 7) /* (W26) RGMII6_RXC.GPIO0_104 */
>;
};......
1、pinctrl驱动为soc厂商单独驱动
2、通用pinctrl驱动,compatible="pinctrl-single",引脚节点属性用pinctrl-single,pins进行配置
2.2 pinctrl子系统注册过程
2.2.1 注册过程
1、准备struct pinctrl_desc数据结构,pinctrl_pin_desc数据类里面会存所有的pin脚,包括每个pin脚的名字,每个pin脚在该pin controller的编号,npins指示多少个pin脚,pctlops,pmxops,confops提供相应的操作函数。
/**
* struct pinctrl_desc - pin controller descriptor, register this to pin
* control subsystem
* @name: name for the pin controller
* @pins: an array of pin descriptors describing all the pins handled by
* this pin controller
* @npins: number of descriptors in the array, usually just ARRAY_SIZE()
* of the pins field above
* @pctlops: pin control operation vtable, to support global concepts like
* grouping of pins, this is optional.
* @pmxops: pinmux operations vtable, if you support pinmuxing in your driver
* @confops: pin config operations vtable, if you support pin configuration in
* your driver
* @owner: module providing the pin controller, used for refcounting
* @num_custom_params: Number of driver-specific custom parameters to be parsed
* from the hardware description
* @custom_params: List of driver_specific custom parameters to be parsed from
* the hardware description
* @custom_conf_items: Information how to print @params in debugfs, must be
* the same size as the @custom_params, i.e. @num_custom_params
*/
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
};
/**
* struct pinctrl_dev - pin control class device
* @node: node to include this pin controller in the global pin controller list
* @desc: the pin controller descriptor supplied when initializing this pin
* controller
* @pin_desc_tree: each pin descriptor for this pin controller is stored in
* this radix tree
* @pin_group_tree: optionally each pin group can be stored in this radix tree
* @num_groups: optionally number of groups can be kept here
* @pin_function_tree: optionally each function can be stored in this radix tree
* @num_functions: optionally number of functions can be kept here
* @gpio_ranges: a list of GPIO ranges that is handled by this pin controller,
* ranges are added to this list at runtime
* @dev: the device entry for this pin controller
* @owner: module providing the pin controller, used for refcounting
* @driver_data: driver data for drivers registering to the pin controller
* subsystem
* @p: result of pinctrl_get() for this device
* @hog_default: default state for pins hogged by this device
* @hog_sleep: sleep state for pins hogged by this device
* @mutex: mutex taken on each pin controller specific action
* @device_root: debugfs root for this device
*/
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
};
ctrldesc->name = "rockchip-pinctrl";
ctrldesc->owner = THIS_MODULE;
ctrldesc->pctlops = &rockchip_pctrl_ops;
ctrldesc->pmxops = &rockchip_pmx_ops;
ctrldesc->confops = &rockchip_pinconf_ops;
pindesc = devm_kcalloc(&pdev->dev,
info->ctrl->nr_pins, sizeof(*pindesc),
GFP_KERNEL);
if (!pindesc)
return -ENOMEM;
ctrldesc->pins = pindesc;
ctrldesc->npins = info->ctrl->nr_pins;
pdesc = pindesc;
for (bank = 0, k = 0; bank < info->ctrl->nr_banks; bank++) {
pin_bank = &info->ctrl->pin_banks[bank];
for (pin = 0; pin < pin_bank->nr_pins; pin++, k++) {
pdesc->number = k;
pdesc->name = kasprintf(GFP_KERNEL, "%s-%d",
pin_bank->name, pin);
pdesc++;
}
}
2、将pinctrl_desc数据结构,私有结构info传递给devm_pinctrl_register进行注册,会返回一个struct pinctrl_dev,所有信息填充在pinctrl_dev,可以将pinctrl_dev看作是pin controller的一个实例。
info->pctl_dev = devm_pinctrl_register(&pdev->dev, ctrldesc, info);
2.2.2 devm_pinctrl_register函数说明
devm_pinctrl_register---->pinctrl_register------->pinctrl_init_controller
|
|
----->pinctrl_enable
static struct pinctrl_dev *pinctrl_init_controller(struct pinctrl_desc *pctldesc, struct device *dev,
void *driver_data)
1、分配一个pinctrl_dev
pctldev = kzalloc(sizeof(*pctldev), GFP_KERNEL);
2、填充pinctrl_dev,前面传递过来的描述pin conroller的数据结构pinctrl_desc,pinctrl的驱动的私有数据结构都填充到pinctrl_dev,dev赋值为设备树pinctrl节点设备
/* Initialize pin control device struct */
pctldev->owner = pctldesc->owner;
pctldev->desc = pctldesc;
pctldev->driver_data = driver_data;
.....
pctldev->dev = dev;
3、初始化三个基数树,两个链表,
pin_desc_tree:存放描述pin的数据结构struct pin_desc,pctldesc->pins也存放有数组方式存放的描述pin的struct pinctrl_pin_desc
pin_group_tree:存放struct group_desc的基数树,某个功能的pin组信息,map转setting的时候,枚举比对name,拿到group的全局编号,私有驱动可以自己的方式存放
pin_function_tree:存放struct function_desc,某个功能的描述信息,map转setting的时候,枚举比对name,拿到func的全局编号,私有驱动可以自己的方式存放
node:挂载到全局变量pinctrldev_list,创建pinctrl的时候会通过pin脚节点查找父目录pinctrl dev节点,枚举pinctrldev_list,比对of_node来查找pin脚节点对应的pinctrl dev
gpio_ranges:struct pinctrl_gpio_range信息挂载链表
list_add_tail(&pctldev->node, &pinctrldev_list);
INIT_RADIX_TREE(&pctldev->pin_desc_tree, GFP_KERNEL);
#ifdef CONFIG_GENERIC_PINCTRL_GROUPS
INIT_RADIX_TREE(&pctldev->pin_group_tree, GFP_KERNEL);
#endif
#ifdef CONFIG_GENERIC_PINMUX_FUNCTIONS
INIT_RADIX_TREE(&pctldev->pin_function_tree, GFP_KERNEL);
#endif
INIT_LIST_HEAD(&pctldev->gpio_ranges);
INIT_LIST_HEAD(&pctldev->node);
4、将pctldesc->pins以数组存放的描述pin的数据结构struct pinctrl_pin_desc以基数树的形式再存到pctldev->pin_desc_tree中
ret = pinctrl_register_pins(pctldev, pctldesc->pins, pctldesc->npins);
......
static int pinctrl_register_pins(struct pinctrl_dev *pctldev,
const struct pinctrl_pin_desc *pins,
unsigned num_descs)
{
unsigned i;
int ret = 0;
for (i = 0; i < num_descs; i++) {
ret = pinctrl_register_one_pin(pctldev, &pins[i]);
if (ret)
return ret;
}
return 0;
}
......
static int pinctrl_register_one_pin(struct pinctrl_dev *pctldev,
const struct pinctrl_pin_desc *pin)
{
struct pin_desc *pindesc;
pindesc = pin_desc_get(pctldev, pin->number);
if (pindesc) {
dev_err(pctldev->dev, "pin %d already registered\n",
pin->number);
return -EINVAL;
}
pin