博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
kernel - pinctrl (二)
阅读量:5214 次
发布时间:2019-06-14

本文共 10258 字,大约阅读时间需要 34 分钟。

一、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 error\n");            return -1;        }        leds_pin_state = pinctrl_lookup_state(leds_pctrl, "leds_active");        if (IS_ERR(leds_pin_state))        {            printk(KERN_ERR "pinctrl_lookup_state error\n");            return -1;        }        ret = pinctrl_select_state(leds_pctrl, leds_pin_state);        if (ret < 0)        {            printk(KERN_ERR "pinctrl_select_state error\n");            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 pinctrl\n");        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 pinctrl\n");        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 phandle\n",                    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_map\n");        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_setting\n");        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

你可能感兴趣的文章
树莓派开发板入门学习笔记2:[转]树莓派系统在VM中能做什么
查看>>
利用F#编写、理解Y组合子函数
查看>>
C#基础-异常处理与自定义异常
查看>>
1. 什么是hash
查看>>
JavaScript Window Screen
查看>>
shell 引号
查看>>
error C2143 & error C4430
查看>>
JDK安装和环境配置
查看>>
assert 与if
查看>>
Python 字典值相加
查看>>
js-ajax相关基础知识整理
查看>>
word2016_添加标题和目录
查看>>
不同颜色空间的转换
查看>>
Oracle扩展的统计信息
查看>>
斐波那契数列的各种求法
查看>>
光固化打印后处理过程
查看>>
曙光I620 -G30 配置 raid 步骤
查看>>
【js】字符串反转可实现的几种方式
查看>>
poj 3126 Prime Path bfs求最短路
查看>>
Service和IntentService的区别
查看>>