kernel - pinctrl (一)

一、pinctrl相关数据结构

struct pinctrl_desc {
    const char *name;
    struct pinctrl_pin_desc const *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 
};
  • name pinctrl名称
  • pinctrl_pin_desc 管脚描述结构体
  • npins 管脚个数
struct pinctrl_pin_desc {
    unsigned number;
    const char *name;
    void *drv_data;
};
  • number管脚编号
  • 管脚名字
struct pinctrl_dev {
    struct list_head node;
    struct pinctrl_desc *desc;
    struct radix_tree_root pin_desc_tree;
    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_desc创建pinctrl_dev并注册到系统中
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 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_state {
    struct list_head node;
    const char *name;
    struct list_head settings;
};

struct pinctrl_dt_map {
    struct list_head node;
    struct pinctrl_dev *pctldev;
    struct pinctrl_map *map;
    unsigned num_maps;
};

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;
};
  • pinctrl为具体驱动程序使用pinctrl接口,将pinctrl和对应的设备相关联
/* List of pin controller handles (struct pinctrl) */
static LIST_HEAD(pinctrl_list);
  • pinctrl_list保存系统中所有的pinctrl句柄
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;
};
  • name为设备树中pinctrl的statename
  • dev_name为与pinctrl相关联的设备的名称
  • ctrl_dev_name为pinctldev设备名称

二、pinctrl子系统的debug调试接口

static int __init pinctrl_init(void)
{
    pr_info("initialized pinctrl subsystem\n");
    pinctrl_init_debugfs();
    return 0;
}

/* init early since many drivers really need to initialized pinmux early */
core_initcall(pinctrl_init);
  • 调用pinctrl_init_debugfs初始化debug接口
static void pinctrl_init_debugfs(void)
{
    debugfs_root = debugfs_create_dir("pinctrl", NULL);
    if (IS_ERR(debugfs_root) || !debugfs_root) {
        pr_warn("failed to create debugfs directory\n");
        debugfs_root = NULL;
        return;
    }

    debugfs_create_file("pinctrl-devices", S_IFREG | S_IRUGO,
                debugfs_root, NULL, &pinctrl_devices_ops);
    debugfs_create_file("pinctrl-maps", S_IFREG | S_IRUGO,
                debugfs_root, NULL, &pinctrl_maps_ops);
    debugfs_create_file("pinctrl-handles", S_IFREG | S_IRUGO,
                debugfs_root, NULL, &pinctrl_ops);
}
  • 创建inctrl-devices、pinctrl-maps、pinctrl-handles接口

三、pinctrl设备注册

/**
 * pinctrl_register() - register a pin controller device
 * @pctldesc: descriptor for this pin controller
 * @dev: parent device for this pin controller
 * @driver_data: private pin controller data for this pin controller
 */
struct pinctrl_dev *pinctrl_register(struct pinctrl_desc *pctldesc,
                    struct device *dev, void *driver_data)
{

    ......
    
    pctldev = kzalloc(sizeof(*pctldev), GFP_KERNEL);
    if (pctldev == NULL) {
        dev_err(dev, "failed to alloc struct pinctrl_dev\n");
        return NULL;
    }

    /* Initialize pin control device struct */
    pctldev->owner = pctldesc->owner;
    pctldev->desc = pctldesc;
    pctldev->driver_data = driver_data;
    INIT_RADIX_TREE(&pctldev->pin_desc_tree, GFP_KERNEL);
    INIT_LIST_HEAD(&pctldev->gpio_ranges);
    pctldev->dev = dev;
    mutex_init(&pctldev->mutex);

    ......
    
    /* Register all the pins */
    dev_dbg(dev, "try to register %d pins ...\n",  pctldesc->npins);
    ret = pinctrl_register_pins(pctldev, pctldesc->pins, pctldesc->npins);
    if (ret) {
        dev_err(dev, "error during pin registration\n");
        pinctrl_free_pindescs(pctldev, pctldesc->pins,
                      pctldesc->npins);
        goto out_err;
    }

    mutex_lock(&pinctrldev_list_mutex);
    list_add_tail(&pctldev->node, &pinctrldev_list);
    mutex_unlock(&pinctrldev_list_mutex);

    pctldev->p = pinctrl_get(pctldev->dev);

    if (!IS_ERR(pctldev->p)) {
        pctldev->hog_default =
            pinctrl_lookup_state(pctldev->p, PINCTRL_STATE_DEFAULT);
        if (IS_ERR(pctldev->hog_default)) {
            dev_dbg(dev, "failed to lookup the default state\n");
        } else {
            if (pinctrl_select_state(pctldev->p,
                        pctldev->hog_default))
                dev_err(dev,
                    "failed to select default state\n");
        }

        pctldev->hog_sleep =
            pinctrl_lookup_state(pctldev->p,
                            PINCTRL_STATE_SLEEP);
        if (IS_ERR(pctldev->hog_sleep))
            dev_dbg(dev, "failed to lookup the sleep state\n");
    }

    pinctrl_init_device_debugfs(pctldev);

    return pctldev;

out_err:
    mutex_destroy(&pctldev->mutex);
    kfree(pctldev);
    return NULL;
}
  • 动态创建pinctrl_dev
  • 调用pinctrl_register_pins注册管脚
  • 将pctldev添加到pinctrldev_list链表中
  • 初始化hog管脚状态(iomux设备的Pinctrl配置)
  • 最后调用pinctrl_init_device_debugfs注册debugfs调试接口
static void pinctrl_init_device_debugfs(struct pinctrl_dev *pctldev)
{
    struct dentry *device_root;

    device_root = debugfs_create_dir(dev_name(pctldev->dev),
                     debugfs_root);
    pctldev->device_root = device_root;

    if (IS_ERR(device_root) || !device_root) {
        pr_warn("failed to create debugfs directory for %s\n",
            dev_name(pctldev->dev));
        return;
    }
    debugfs_create_file("pins", S_IFREG | S_IRUGO,
                device_root, pctldev, &pinctrl_pins_ops);
    debugfs_create_file("pingroups", S_IFREG | S_IRUGO,
                device_root, pctldev, &pinctrl_groups_ops);
    debugfs_create_file("gpio-ranges", S_IFREG | S_IRUGO,
                device_root, pctldev, &pinctrl_gpioranges_ops);
    if (pctldev->desc->pmxops)
        pinmux_init_device_debugfs(device_root, pctldev);
    if (pctldev->desc->confops)
        pinconf_init_device_debugfs(device_root, pctldev);
}
  • 首先创建pins、pingroups、gpio-ranges三个调试接口
  • 调用pinmux_init_device_debugfs创建pinmux相关调试接口pinmux-functions、pinmux-pins
  • 调用pinconf_init_device_debugfs创建pinconf相关调试接口pinconf-pins、pinconf-groups、pinconf-config

转载于:https://www.cnblogs.com/qzhang1535/p/10910083.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值