linux gpio子系统与pinctrl子系统

一、pinctrl与gpio子系统概述

1.1 gpio子系统

主要负责读/写引脚值、设置引脚为输入或输出模式、中断等基本操作。

1.2 pinctrl子系统

管理所有可控制的引脚,包括引脚的复用功能、电气特性等。‌

1.2.1 pinctrl子系统的主要功能包括

  1. ‌引脚复用‌:大多数引脚都可以通过配置寄存器来选择复用成不同的功能。
  2. ‌引脚配置‌:包括设置引脚的上拉/下拉电阻、速度、驱动能力等电气特性。

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值