我是靠谱客的博主 深情期待,最近开发中收集的这篇文章主要介绍kernel - pinctrl (二),觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

一、pinctrl的接口使用示例

// 以下是一个使用pinctrl的简单例子
static int leds_probe(struct platform_device * pdev)
{
        ......

        struct pinctrl * leds_pctrl;
        struct pinctrl_state * leds_pin_state;

        leds_pctrl = devm_pinctrl_get(&pdev->dev);   //
        if (IS_ERR(leds_pctrl)) {
            printk("devm_pinctrl_get errorn");
            return -1;
        }

        leds_pin_state = pinctrl_lookup_state(leds_pctrl, "leds_active");
        if (IS_ERR(leds_pin_state))
        {
            printk(KERN_ERR "pinctrl_lookup_state errorn");
            return -1;
        }

        ret = pinctrl_select_state(leds_pctrl, leds_pin_state);
        if (ret < 0)
        {
            printk(KERN_ERR "pinctrl_select_state errorn");
            return -1;
        }
        ......

        return 0;
}
  • 调用devm_pinctrl_get获取pinctrl句柄,devm_pinctrl_get实际调用pinctrl_get
  • 调用pinctrl_lookup_state查询所需的pinctrl_state
  • 调用pinctrl_select_state设置对应管脚状态

二、pinctrl的接口分析

struct pinctrl *pinctrl_get(struct device *dev)
{
    struct pinctrl *p;

    if (WARN_ON(!dev))
        return ERR_PTR(-EINVAL);

    /*
     * See if somebody else (such as the device core) has already
     * obtained a handle to the pinctrl for this device. In that case,
     * return another pointer to it.
     */
    p = find_pinctrl(dev);
    if (p != NULL) {
        dev_dbg(dev, "obtain a copy of previously claimed pinctrln");
        kref_get(&p->users);
        return p;
    }

    return create_pinctrl(dev);
}
  • 首先调用find_pinctrl函数查找pinctrl句柄,如果找到就直接返回
  • 如果find_pinctrl没有找到pinctrl句柄, 则创建create_pinctrl
static struct pinctrl *find_pinctrl(struct device *dev)
{
    struct pinctrl *p;

    mutex_lock(&pinctrl_list_mutex);
    list_for_each_entry(p, &pinctrl_list, node)
        if (p->dev == dev) {
            mutex_unlock(&pinctrl_list_mutex);
            return p;
        }

    mutex_unlock(&pinctrl_list_mutex);
    return NULL;
}
  • 遍历pinctrl_list查找与dev相匹配的设备pinctrl句柄
static struct pinctrl *create_pinctrl(struct device *dev)
{
    struct pinctrl *p;
    const char *devname;
    struct pinctrl_maps *maps_node;
    int i;
    struct pinctrl_map const *map;
    int ret;

    /*
     * create the state cookie holder struct pinctrl for each
     * mapping, this is what consumers will get when requesting
     * a pin control handle with pinctrl_get()
     */
    p = kzalloc(sizeof(*p), GFP_KERNEL);
    if (p == NULL) {
        dev_err(dev, "failed to alloc struct pinctrln");
        return ERR_PTR(-ENOMEM);
    }
    p->dev = dev;
    INIT_LIST_HEAD(&p->states);
    INIT_LIST_HEAD(&p->dt_maps);

    ret = pinctrl_dt_to_map(p);
    if (ret < 0) {
        kfree(p);
        return ERR_PTR(ret);
    }

    devname = dev_name(dev);

    mutex_lock(&pinctrl_maps_mutex);
    /* Iterate over the pin control maps to locate the right ones */
    for_each_maps(maps_node, i, map) {
        /* Map must be for this device */
        if (strcmp(map->dev_name, devname))
            continue;

        ret = add_setting(p, map);
        /*
         * At this point the adding of a setting may:
         *
         * - Defer, if the pinctrl device is not yet available
         * - Fail, if the pinctrl device is not yet available,
         *   AND the setting is a hog. We cannot defer that, since
         *   the hog will kick in immediately after the device
         *   is registered.
         *
         * If the error returned was not -EPROBE_DEFER then we
         * accumulate the errors to see if we end up with
         * an -EPROBE_DEFER later, as that is the worst case.
         */
        if (ret == -EPROBE_DEFER) {
            pinctrl_free(p, false);
            mutex_unlock(&pinctrl_maps_mutex);
            return ERR_PTR(ret);
        }
    }
    mutex_unlock(&pinctrl_maps_mutex);

    if (ret < 0) {
        /* If some other error than deferral occured, return here */
        pinctrl_free(p, false);
        return ERR_PTR(ret);
    }

    kref_init(&p->users);

    /* Add the pinctrl handle to the global list */
    mutex_lock(&pinctrl_list_mutex);
    list_add_tail(&p->node, &pinctrl_list);
    mutex_unlock(&pinctrl_list_mutex);

    return p;
}
  • 动态创建pinctrl并进行相应初始化工作
  • 调用pinctrl_dt_to_map将pinctrl设备树解析为pinctrl_map,并注册到pinctrl_maps
  • 查找pinctrl_maps,调用add_setting将相应的map添加到pinctrl
  • 将pinctrl添加到pinctrl_list以便于后面查找
int pinctrl_dt_to_map(struct pinctrl *p)
{
    ......
    /* For each defined state ID */
    for (state = 0; ; state++) {
        ......
        /* For every referenced pin configuration node in it */
        for (config = 0; config < size; config++) {
            phandle = be32_to_cpup(list++);

            /* Look up the pin configuration node */
            np_config = of_find_node_by_phandle(phandle);
            if (!np_config) {
                dev_err(p->dev,
                    "prop %s index %i invalid phandlen",
                    prop->name, config);
                ret = -EINVAL;
                goto err;
            }

            /* Parse the node */
            ret = dt_to_map_one_config(p, statename, np_config);
            of_node_put(np_config);
            if (ret < 0)
                goto err;
        }

        .......
    }

    ......
}
  • 首先找到对应的设备树结点np_config
  • 然后调用dt_to_map_one_config去解析设备树
static int dt_to_map_one_config(struct pinctrl *p, const char *statename,
    ......
    
    ret = ops->dt_node_to_map(pctldev, np_config, &map, &num_maps);
    if (ret < 0)
        return ret;
        
    /* Stash the mapping table chunk away for later use */
    return dt_remember_or_free_map(p, statename, pctldev, map, num_maps);
}   
  • 调用pctldev->desc->pctlops的dt_node_to_map函数去解析设备树(与具体的pinctrl控制器有关)
  • 调用dt_remember_or_free_map去注册map
static int dt_remember_or_free_map(struct pinctrl *p, const char *statename,
                   struct pinctrl_dev *pctldev,
                   struct pinctrl_map *map, unsigned num_maps)
{
    int i;
    struct pinctrl_dt_map *dt_map;

    /* Initialize common mapping table entry fields */
    for (i = 0; i < num_maps; i++) {
        map[i].dev_name = dev_name(p->dev);
        map[i].name = statename;
        if (pctldev)
            map[i].ctrl_dev_name = dev_name(pctldev->dev);
    }

    /* Remember the converted mapping table entries */
    dt_map = kzalloc(sizeof(*dt_map), GFP_KERNEL);
    if (!dt_map) {
        dev_err(p->dev, "failed to alloc struct pinctrl_dt_mapn");
        dt_free_map(pctldev, map, num_maps);
        return -ENOMEM;
    }

    dt_map->pctldev = pctldev;
    dt_map->map = map;
    dt_map->num_maps = num_maps;
    list_add_tail(&dt_map->node, &p->dt_maps);

    return pinctrl_register_map(map, num_maps, false);
}
  • 动态分配dt_map,然后注册到pinctrl上
  • 调用pinctrl_register_map创建pinctrl_maps,并将mpinctrl_maps注册到pinctrl_maps链表上,至此pinctrl_dt_to_map的工作基本完成,继续回到create_pinctrl
static int add_setting(struct pinctrl *p, struct pinctrl_map const *map)
{
    struct pinctrl_state *state;
    struct pinctrl_setting *setting;
    int ret;

    state = find_state(p, map->name);
    if (!state)
        state = create_state(p, map->name);
    if (IS_ERR(state))
        return PTR_ERR(state);

    if (map->type == PIN_MAP_TYPE_DUMMY_STATE)
        return 0;

    setting = kzalloc(sizeof(*setting), GFP_KERNEL);
    if (setting == NULL) {
        dev_err(p->dev,
            "failed to alloc struct pinctrl_settingn");
        return -ENOMEM;
    }

    setting->type = map->type;

    setting->pctldev = get_pinctrl_dev_from_devname(map->ctrl_dev_name);
    if (setting->pctldev == NULL) {
        kfree(setting);
        /* Do not defer probing of hogs (circular loop) */
        if (!strcmp(map->ctrl_dev_name, map->dev_name))
            return -ENODEV;
        /*
         * OK let us guess that the driver is not there yet, and
         * let's defer obtaining this pinctrl handle to later...
         */
        dev_info(p->dev, "unknown pinctrl device %s in map entry, deferring probe",
            map->ctrl_dev_name);
        return -EPROBE_DEFER;
    }

    setting->dev_name = map->dev_name;

    switch (map->type) {
    case PIN_MAP_TYPE_MUX_GROUP:
        ret = pinmux_map_to_setting(map, setting);
        break;
    case PIN_MAP_TYPE_CONFIGS_PIN:
    case PIN_MAP_TYPE_CONFIGS_GROUP:
        ret = pinconf_map_to_setting(map, setting);
        break;
    default:
        ret = -EINVAL;
        break;
    }
    if (ret < 0) {
        kfree(setting);
        return ret;
    }

    list_add_tail(&setting->node, &state->settings);

    return 0;
}
  • 根据pinctrl和map名称查找state,如果没有找到就创建
  • 动态创建setting并初始化,然后添加到state的settings链表上
struct pinctrl_state *pinctrl_lookup_state(struct pinctrl *p, 
                         const char *name)                        
{
    struct pinctrl_state *state;        

    state = find_state(p, name);        
    if (!state) {
        if (pinctrl_dummy_state) {      
            /* create dummy state */    
            dev_dbg(p->dev, "using pinctrl dummy state (%s)n",
                name);
            state = create_state(p, name);           
        } else
            state = ERR_PTR(-ENODEV);   
    }  

    return state;
}
  • 根据名称查找pinctrl里的state,返回pinctrl_state
int pinctrl_select_state(struct pinctrl *p, struct pinctrl_state *state)
{
    struct pinctrl_setting *setting, *setting2;
    struct pinctrl_state *old_state = p->state;
    int ret;

    if (p->state == state)
        return 0;

    if (p->state) {
        /*
         * For each pinmux setting in the old state, forget SW's record
         * of mux owner for that pingroup. Any pingroups which are
         * still owned by the new state will be re-acquired by the call
         * to pinmux_enable_setting() in the loop below.
         */
        list_for_each_entry(setting, &p->state->settings, node) {
            if (setting->type != PIN_MAP_TYPE_MUX_GROUP)
                continue;
            pinmux_disable_setting(setting);
        }
    }   
    
    p->state = NULL; 
        
    /* Apply all the settings for the new state */
    list_for_each_entry(setting, &state->settings, node) {
        switch (setting->type) {
        case PIN_MAP_TYPE_MUX_GROUP:
            ret = pinmux_enable_setting(setting);
            break;
        case PIN_MAP_TYPE_CONFIGS_PIN:
        case PIN_MAP_TYPE_CONFIGS_GROUP:
            ret = pinconf_apply_setting(setting);
            break;
        default:
            ret = -EINVAL;
            break;
        }

        if (ret < 0) {
            goto unapply_new_state;
        }
    }

    p->state = state;

    ......
}
  • 调用pinmux_enable_setting和pinconf_apply_setting应用相应settings

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

最后

以上就是深情期待为你收集整理的kernel - pinctrl (二)的全部内容,希望文章能够帮你解决kernel - pinctrl (二)所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(41)

评论列表共有 0 条评论

立即
投稿
返回
顶部