pinctrl子系统


怎么整

想搞明白是什么, 怎么用, 前因后果是什么, 建议去看官方文档, 静下心分开时间去看完, 会收获很多.

https://www.kernel.org/doc/html/latest/driver-api/pin-control.html

 驱动开发流程

1. Linux内核开发者对驱动框架进行开发和维护、升级, 向上层提供api接口进行注册和使用(大牛)
2. soc厂商工程师针对芯片进行数据的封装调用框架提供的api接口进行注册(二牛)
3. 驱动工程师对soc厂商出的产品的驱动进行移植和调试, 也是调用框架提供的api接口(消费者)进行使用

 分析

小弟能力有限, 水平一般

提前说声, 这个pinxtrl子系统的使用只需要修改设备树, 利用平台设备驱动对设备树的匹配来进行配置.(未使用设备树的没有研究)

设备树和平台设备驱动要了解

```
通过官方文档, 顶层接口是
struct pinctrl_dev *devm_pinctrl_register(struct device *dev,
                      struct pinctrl_desc *pctldesc,
                      void *driver_data);
或者
int devm_pinctrl_register_and_init(struct device *dev,
                   struct pinctrl_desc *pctldesc,
                   void *driver_data,
                   struct pinctrl_dev **pctldev);
int pinctrl_enable(struct pinctrl_dev *pctldev);               

还有没有加devm的

先看几个结构体
struct pinctrl_pin_desc {   //引脚描述符
    unsigned number;  //全局pin号空间的唯一pin号
    const char *name; //pin号的名字
    void *drv_data;  //driver-defined per-pin数据。Pinctrl core不碰这个
};


struct pinctrl_desc { //引脚控制器描述符,将此注册到引脚控制器子系统
    const char *name; //名字
    const struct pinctrl_pin_desc *pins; //所有引脚的引脚描述符数组
    unsigned int npins; //引脚描述符数组的数量, 通常使用ARRAY_SIZE()
    const struct pinctrl_ops *pctlops;//引脚控制操作虚拟函数, 可选
    const struct pinmux_ops *pmxops; //pinmux操作虚拟函数
    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; //有关如何在 debugfs 中打印 @params 的信息,必须是与@custom_params 相同的大小
#endif
    bool link_consumers; //如果为真,则在pinctrl和its之间创建一个设备链接,这是有时需要确定正确的暂停/恢复的例子
};


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
};


//分析pinctrl_register
struct pinctrl_dev *pinctrl_register(struct pinctrl_desc *pctldesc,
                    struct device *dev, void *driver_data) //参数是pinctrl_desc结构体, device结构体, 私有数据 driver_data
{
    struct pinctrl_dev *pctldev;
    int error;

    pctldev = pinctrl_init_controller(pctldesc, dev, driver_data); //pinctrl控制器初始化并返回pinctrl_dev结构体
    if (IS_ERR(pctldev))
        return pctldev;

    error = pinctrl_enable(pctldev);  //使能 pinctrl
    if (error)
        return ERR_PTR(error);

    return pctldev;

}

//分析pinctrl_init_controller
static struct pinctrl_dev *
pinctrl_init_controller(struct pinctrl_desc *pctldesc, struct device *dev,
            void *driver_data)
{
    struct pinctrl_dev *pctldev;
    int ret;

    if (!pctldesc)
        return ERR_PTR(-EINVAL);
    if (!pctldesc->name)
        return ERR_PTR(-EINVAL);

    pctldev = kzalloc(sizeof(*pctldev), GFP_KERNEL);  //创建pinctrl_dev结构体
    if (!pctldev)
        return ERR_PTR(-ENOMEM);

    /* Initialize pin control device struct */
    pctldev->owner = pctldesc->owner;  //赋予owner
    pctldev->desc = pctldesc;   //你中有我
    pctldev->driver_data = driver_data; //赋予私有数据
    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);  //初始化链表
    pctldev->dev = dev;  //赋予device
    mutex_init(&pctldev->mutex);  //初始化锁

    /* check core ops for sanity */
    ret = pinctrl_check_ops(pctldev); //检查核心操作是否正常
    if (ret) {
        dev_err(dev, "pinctrl ops lacks necessary functions\n");
        goto out_err;
    }

    /* If we're implementing pinmuxing, check the ops for sanity */
    if (pctldesc->pmxops) {            
        ret = pinmux_check_ops(pctldev);  //如果实现pinmuxing,检查操作是否正常
        if (ret)
            goto out_err;
    }

    /* If we're implementing pinconfig, check the ops for sanity */
    if (pctldesc->confops) {
        ret = pinconf_check_ops(pctldev); //如果实现pinconfig,检查操作是否正常
        if (ret)
            goto out_err;
    }

    /* 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;
    }

    return pctldev;

out_err:
    mutex_destroy(&pctldev->mutex);
    kfree(pctldev);
    return ERR_PTR(ret);
}


//分析pinctrl_register_pins
static int pinctrl_register_pins(struct pinctrl_dev *pctldev,
                 const struct pinctrl_pin_desc *pins,
                 unsigned num_descs) //参数 pinctrl_dev结构体, pinctrl_pin_desc结构体, num_descs 个 pinctrl_pin_desc结构体
{
    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;
}

//分析pinctrl_register_pins
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);   //通过key在基数树中取值,若有值有问题
    if (pindesc) {
        dev_err(pctldev->dev, "pin %d already registered\n",
            pin->number);
        return -EINVAL;
    }

    pindesc = kzalloc(sizeof(*pindesc), GFP_KERNEL); //创建pin_desc结构体
    if (!pindesc)
        return -ENOMEM;

    /* Set owner */
    pindesc->pctldev = pctldev; //你中有我

    /* Copy basic pin info */
    if (pin->name) {
        pindesc->name = pin->name;      //赋予名字
    } else {
        pindesc->name = kasprintf(GFP_KERNEL, "PIN%u", pin->number);  //赋予自定义名字
        if (!pindesc->name) {
            kfree(pindesc);
            return -ENOMEM;
        }
        pindesc->dynamic_name = true;  //标识是动态的名字
    }

    pindesc->drv_data = pin->drv_data; //赋予数据

    radix_tree_insert(&pctldev->pin_desc_tree, pin->number, pindesc);  //把pin->number作为key加入基数树中
    pr_debug("registered pin %d (%s) on %s\n",
         pin->number, pindesc->name, pctldev->desc->name);
    return 0;
}


//--------总结pinctrl_init_controller------
- 创建pinctrl_dev, 初始化该结构体的链表, 基数树, 锁, 私有数据等
- 检测核心操作, pinmuxing, pinconfig
- 将每个引脚封装pin_desc结构体加入基数树中


//分析pinctrl_enable
int pinctrl_enable(struct pinctrl_dev *pctldev)
{
    int error;

    error = pinctrl_claim_hogs(pctldev);    //不知道翻译什么好
    if (error) {
        dev_err(pctldev->dev, "could not claim hogs: %i\n",
            error);
        mutex_destroy(&pctldev->mutex);
        kfree(pctldev);

        return error;
    }

    mutex_lock(&pinctrldev_list_mutex);
    list_add_tail(&pctldev->node, &pinctrldev_list);   //将pinctrl_dev加入pinctrldev_list链表中
    mutex_unlock(&pinctrldev_list_mutex);

    pinctrl_init_device_debugfs(pctldev);  //关于debug的

    return 0;
}

//分析pinctrl_claim_hogs
static int pinctrl_claim_hogs(struct pinctrl_dev *pctldev)
{
    pctldev->p = create_pinctrl(pctldev->dev, pctldev);      //创建pinctrl结构体, 这个很重要
    if (PTR_ERR(pctldev->p) == -ENODEV) {
        dev_dbg(pctldev->dev, "no hogs found\n");

        return 0;
    }

    if (IS_ERR(pctldev->p)) {
        dev_err(pctldev->dev, "error claiming hogs: %li\n",
            PTR_ERR(pctldev->p));

        return PTR_ERR(pctldev->p);
    }

    pctldev->hog_default =
        pinctrl_lookup_state(pctldev->p, PINCTRL_STATE_DEFAULT);  //首先在pinctrl的states链表中匹配名字为"default"的pinctrl_state, 若没有就创建, 并赋予给pinctrl_dev中hog_default
    if (IS_ERR(pctldev->hog_default)) {
        dev_dbg(pctldev->dev,
            "failed to lookup the default state\n");
    } else {
        if (pinctrl_select_state(pctldev->p,  
                     pctldev->hog_default))                    //选择默认状态
            dev_err(pctldev->dev,
                "failed to select default state\n");
    }

    pctldev->hog_sleep =
        pinctrl_lookup_state(pctldev->p,
                     PINCTRL_STATE_SLEEP);       首先在pinctrl的states链表中匹配名字为"sleep"的pinctrl_state, 若没有就创建, 并赋予给pinctrl_dev中hog_sleep
    if (IS_ERR(pctldev->hog_sleep))
        dev_dbg(pctldev->dev,
            "failed to lookup the sleep state\n");

    return 0;
}


//分析create_pinctrl
static struct pinctrl *create_pinctrl(struct device *dev,
                      struct pinctrl_dev *pctldev)
{
    struct pinctrl *p;
    const char *devname;
    struct pinctrl_maps *maps_node;
    int i;
    const struct pinctrl_map *map;
    int ret;
    
     //为每个映射创建状态cookiholder结构pinctrl,这是消费者在使用pinctrl_get()请求pin控制句柄时将得到的结果
    /*
     * 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);    //创建pinctrl结构体
    if (!p)
        return ERR_PTR(-ENOMEM);
    p->dev = dev;  //赋予device
    INIT_LIST_HEAD(&p->states);  //初始化链表
    INIT_LIST_HEAD(&p->dt_maps); 初始化链表

    ret = pinctrl_dt_to_map(p, pctldev);  //设备树的数据映射
    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) {      //双重循环, 先是pinctrl_maps链表中找到pinctrl_maps,再从中找到多个的pinctrl_map
        /* Map must be for this device */
        if (strcmp(map->dev_name, devname))
            continue;
        /*
         * If pctldev is not null, we are claiming hog for it,
         * that means, setting that is served by pctldev by itself.
         *
         * Thus we must skip map that is for this device but is served
         * by other device.
         */
        if (pctldev &&
            strcmp(dev_name(pctldev->dev), map->ctrl_dev_name))
            continue;

        ret = add_setting(p, pctldev, 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 occurred, 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);  //将pinctrl添加到pinctrl_list链表中
    mutex_unlock(&pinctrl_list_mutex);

    return p;
}

//分析pinctrl_dt_to_map
int pinctrl_dt_to_map(struct pinctrl *p, struct pinctrl_dev *pctldev)
{
    struct device_node *np = p->dev->of_node;  //从device中拿到设备节点
    int state, ret;
    char *propname;
    struct property *prop;
    const char *statename;
    const __be32 *list;
    int size, config;
    phandle phandle;
    struct device_node *np_config;

    /* CONFIG_OF enabled, p->dev not instantiated from DT */
    if (!np) {
        if (of_have_populated_dt())
            dev_dbg(p->dev,
                "no of_node; not parsing pinctrl DT\n");
        return 0;
    }

    /* We may store pointers to property names within the node */
    of_node_get(np);

    /* For each defined state ID */
    for (state = 0; ; state++) {
        /* Retrieve the pinctrl-* property */
        propname = kasprintf(GFP_KERNEL, "pinctrl-%d", state);
        prop = of_find_property(np, propname, &size);     //通过pinctrl-%d拿到属性property结构体 
        kfree(propname);
        if (!prop) {
            if (state == 0) {        //如果pinctrl-0都没有那还扯什么犊子
                of_node_put(np);
                return -ENODEV;
            }
            break;
        }
        list = prop->value;     // void * 的值
        size /= sizeof(*list);  // 有几个值

        /* Determine whether pinctrl-names property names the state */
        ret = of_property_read_string_index(np, "pinctrl-names",
                            state, &statename);   //通过pinctrl-names属性名获取第state个值, 例如: pinctrl-names = "default";
        /*
         * If not, statename is just the integer state ID. But rather
         * than dynamically allocate it and have to free it later,
         * just point part way into the property name for the string.
         */
        if (ret < 0)
            statename = prop->name + strlen("pinctrl-");    //若没有获取到值, 重新自定义

        /* For every referenced pin configuration node in it */
        for (config = 0; config < size; config++) {    //pinctrl-0对应的值进行循环 例如: pinctrl-0 = <&gpioout &alt0>;
            phandle = be32_to_cpup(list++);   //转化为phandle, 则为u32类型

            /* Look up the pin configuration node */
            np_config = of_find_node_by_phandle(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, pctldev, statename,
                           np_config);  //解析节点
            of_node_put(np_config);
            if (ret < 0)
                goto err;
        }

        /* No entries in DT? Generate a dummy state table entry */
        if (!size) {
            ret = dt_remember_dummy_state(p, statename);
            if (ret < 0)
                goto err;
        }
    }

    return 0;

err:
    pinctrl_dt_free_maps(p);
    return ret;
}


//分析dt_to_map_one_config
static int dt_to_map_one_config(struct pinctrl *p,
                struct pinctrl_dev *hog_pctldev,
                const char *statename,
                struct device_node *np_config)
{
    struct pinctrl_dev *pctldev = NULL;
    struct device_node *np_pctldev;
    const struct pinctrl_ops *ops;
    int ret;
    struct pinctrl_map *map;
    unsigned num_maps;
    bool allow_default = false;

    /* Find the pin controller containing np_config */
    np_pctldev = of_node_get(np_config);
    for (;;) {
        if (!allow_default)
            allow_default = of_property_read_bool(np_pctldev,
                                  "pinctrl-use-default");   //获取设备节点的pinctrl-use-default属性的bool值

        np_pctldev = of_get_next_parent(np_pctldev); //获取设备节点的父设备节点, 这里不要晕, 这里的设备节点是phandle值找到设备节点
        if (!np_pctldev || of_node_is_root(np_pctldev)) {
            of_node_put(np_pctldev);
            ret = driver_deferred_probe_check_state(p->dev);
            /* keep deferring if modules are enabled */
            if (IS_ENABLED(CONFIG_MODULES) && !allow_default && ret < 0)
                ret = -EPROBE_DEFER;
            return ret;
        }
        /* If we're creating a hog we can use the passed pctldev */
        if (hog_pctldev && (np_pctldev == p->dev->of_node)) {  //拿到真正的pinctrl_dev结构体, 当注册pinctrl_register时,会执行这里
            pctldev = hog_pctldev;
            break;
        }
        pctldev = get_pinctrl_dev_from_of_node(np_pctldev);   //拿到真正的pinctrl_dev结构体, 当消费者使用时, 会从pinctrldev_list链表获取
        if (pctldev)
            break;
        /* Do not defer probing of hogs (circular loop) */
        if (np_pctldev == p->dev->of_node) {
            of_node_put(np_pctldev);
            return -ENODEV;
        }
    }
    of_node_put(np_pctldev);

    /*
     * Call pinctrl driver to parse device tree node, and
     * generate mapping table entries
     */
    ops = pctldev->desc->pctlops;
    if (!ops->dt_node_to_map) {
        dev_err(p->dev, "pctldev %s doesn't support DT\n",
            dev_name(pctldev->dev));
        return -ENODEV;
    }
    ret = ops->dt_node_to_map(pctldev, np_config, &map, &num_maps);   //pinctrl_dev结构体中有pinctrl_desc结构体, pinctrl_desc结构体中有pinctrl_ops结构体
    if (ret < 0)                                                      //这个pinctrl_ops结构体是芯片工程师进行实现的, 这里目的是获取struct pinctrl_map
        return ret;
    else if (num_maps == 0) {
        /*
         * If we have no valid maps (maybe caused by empty pinctrl node
         * or typing error) ther is no need remember this, so just
         * return.
         */
        dev_info(p->dev,
             "there is not valid maps for state %s\n", statename);
        return 0;
    }

    /* Stash the mapping table chunk away for later use */
    return dt_remember_or_free_map(p, statename, pctldev, map, num_maps);  //将映射表块保存起来,以便以后使用
}    

分析dt_remember_or_free_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++) {
        const char *devname;

        devname = kstrdup_const(dev_name(p->dev), GFP_KERNEL);
        if (!devname)
            goto err_free_map;

        map[i].dev_name = devname;  //pinctrl中的device名
        map[i].name = statename;   //状态名 一般pinctrl-0
        if (pctldev)
            map[i].ctrl_dev_name = dev_name(pctldev->dev); pinctrl_dev中device名
    }

    /* Remember the converted mapping table entries */
    dt_map = kzalloc(sizeof(*dt_map), GFP_KERNEL);  //创建pinctrl_dt_map
    if (!dt_map)
        goto err_free_map;

    dt_map->pctldev = pctldev;
    dt_map->map = map;
    dt_map->num_maps = num_maps;
    list_add_tail(&dt_map->node, &p->dt_maps);  //把pinctl_ma封装成pinctrl_dt_map绑定到pinctrl上

    return pinctrl_register_mappings(map, num_maps); //把pinctrl_map封装成pinctrl_maps放到pinctrl_maps链表上

err_free_map:
    dt_free_map(pctldev, map, num_maps);
    return -ENOMEM;
}


//分析add_setting
static int add_setting(struct pinctrl *p, struct pinctrl_dev *pctldev,
               const struct pinctrl_map *map)
{
    struct pinctrl_state *state;
    struct pinctrl_setting *setting;
    int ret;

    state = find_state(p, map->name); //pinctrl结构中的states链表中通过map->name名字筛选出来
    if (!state)
        state = create_state(p, map->name); //创建pinctrl_state, 赋予名字, 并绑定到pinctrl结构中states中
    if (IS_ERR(state))
        return PTR_ERR(state);

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

    setting = kzalloc(sizeof(*setting), GFP_KERNEL); //创建pinctrl_setting
    if (!setting)
        return -ENOMEM;

    setting->type = map->type;

    if (pctldev)
        setting->pctldev = pctldev;
    else
        setting->pctldev =
            get_pinctrl_dev_from_devname(map->ctrl_dev_name);
    if (!setting->pctldev) {
        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); //pinctrl_map转化为pinctrl_setting
        break;
    case PIN_MAP_TYPE_CONFIGS_PIN:
    case PIN_MAP_TYPE_CONFIGS_GROUP:
        ret = pinconf_map_to_setting(map, setting);  //pinctrl_map转化为pinctrl_setting
        break;
    default:
        ret = -EINVAL;
        break;
    }
    if (ret < 0) {
        kfree(setting);
        return ret;
    }

    list_add_tail(&setting->node, &state->settings);  //pinctrl_setting添加到pinctrl_state的settings的链表中

    return 0;
}

//--------总结create_pinctrl------
- 创建pinctrl
- 设备树的数据进行映射填充pinctrl_map, 转化为pinctrl_dt_map依附到pinctrl, 转化为pinctrl_maps依附到pinctrl_maps链表中
- 将pinctrl_map转化为pinctrl_setting依附到pinctrl_state, pinctrl_state依附到到pinctrl上

//分析pinctrl_select_state  选择状态, 前期是配置数据, 这步要操作寄存器了
int pinctrl_select_state(struct pinctrl *p, struct pinctrl_state *state)
{
    if (p->state == state)  //如果
        return 0;

    return pinctrl_commit_state(p, state);
}

//分析pinctrl_commit_state
static int pinctrl_commit_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) {
        /*
         * 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;
        }

        /* Do not link hogs (circular dependency) */
        if (p != setting->pctldev->p)
            pinctrl_link_add(setting->pctldev, p->dev);
    }

    p->state = state;

    return 0;

unapply_new_state:
    dev_err(p->dev, "Error applying setting, reverse things back\n");

    list_for_each_entry(setting2, &state->settings, node) {
        if (&setting2->node == &setting->node)
            break;
        /*
         * All we can do here is pinmux_disable_setting.
         * That means that some pins are muxed differently now
         * than they were before applying the setting (We can't
         * "unmux a pin"!), but it's not a big deal since the pins
         * are free to be muxed by another apply_setting.
         */
        if (setting2->type == PIN_MAP_TYPE_MUX_GROUP)
            pinmux_disable_setting(setting2);
    }

    /* There's no infinite recursive loop here because p->state is NULL */
    if (old_state)
        pinctrl_select_state(p, old_state);

    return ret;
}

//分析pinmux_enable_setting
int pinmux_enable_setting(const struct pinctrl_setting *setting)
{
    struct pinctrl_dev *pctldev = setting->pctldev;
    const struct pinctrl_ops *pctlops = pctldev->desc->pctlops;
    const struct pinmux_ops *ops = pctldev->desc->pmxops;
    int ret = 0;
    const unsigned *pins = NULL;
    unsigned num_pins = 0;
    int i;
    struct pin_desc *desc;

    if (pctlops->get_group_pins)
        ret = pctlops->get_group_pins(pctldev, setting->data.mux.group,
                          &pins, &num_pins);

    if (ret) {
        const char *gname;

        /* errors only affect debug data, so just warn */
        gname = pctlops->get_group_name(pctldev,
                        setting->data.mux.group);
        dev_warn(pctldev->dev,
             "could not get pins for group %s\n",
             gname);
        num_pins = 0;
    }

    /* Try to allocate all pins in this group, one by one */
    for (i = 0; i < num_pins; i++) {
        ret = pin_request(pctldev, pins[i], setting->dev_name, NULL);  //要求单个引脚被混接,通常用于GPIO
        if (ret) {
            const char *gname;
            const char *pname;

            desc = pin_desc_get(pctldev, pins[i]);
            pname = desc ? desc->name : "non-existing";
            gname = pctlops->get_group_name(pctldev,
                        setting->data.mux.group);
            dev_err(pctldev->dev,
                "could not request pin %d (%s) from group %s "
                " on device %s\n",
                pins[i], pname, gname,
                pinctrl_dev_get_name(pctldev));
            goto err_pin_request;
        }
    }

    /* Now that we have acquired the pins, encode the mux setting */
    for (i = 0; i < num_pins; i++) {
        desc = pin_desc_get(pctldev, pins[i]);
        if (desc == NULL) {
            dev_warn(pctldev->dev,
                 "could not get pin desc for pin %d\n",
                 pins[i]);
            continue;
        }
        desc->mux_setting = &(setting->data.mux);   //多路复用设置
    }

    ret = ops->set_mux(pctldev, setting->data.mux.func,   //关键调用了set_mux函数, 芯片厂商实现的函数, 操作寄存器
               setting->data.mux.group);

    if (ret)
        goto err_set_mux;

    return 0;

err_set_mux:
    for (i = 0; i < num_pins; i++) {
        desc = pin_desc_get(pctldev, pins[i]);
        if (desc)
            desc->mux_setting = NULL;
    }
err_pin_request:
    /* On error release all taken pins */
    while (--i >= 0)
        pin_free(pctldev, pins[i], NULL);

    return ret;
}

//分析pinconf_apply_setting
int pinconf_apply_setting(const struct pinctrl_setting *setting)
{
    struct pinctrl_dev *pctldev = setting->pctldev;
    const struct pinconf_ops *ops = pctldev->desc->confops;
    int ret;

    if (!ops) {
        dev_err(pctldev->dev, "missing confops\n");
        return -EINVAL;
    }

    switch (setting->type) {
    case PIN_MAP_TYPE_CONFIGS_PIN:
        if (!ops->pin_config_set) {
            dev_err(pctldev->dev, "missing pin_config_set op\n");
            return -EINVAL;
        }
        ret = ops->pin_config_set(pctldev,        //调用pin_config_set函数, 芯片厂商实现的函数, 操作寄存器
                setting->data.configs.group_or_pin,
                setting->data.configs.configs,
                setting->data.configs.num_configs);
        if (ret < 0) {
            dev_err(pctldev->dev,
                "pin_config_set op failed for pin %d\n",
                setting->data.configs.group_or_pin);
            return ret;
        }
        break;
    case PIN_MAP_TYPE_CONFIGS_GROUP:
        if (!ops->pin_config_group_set) {
            dev_err(pctldev->dev,
                "missing pin_config_group_set op\n");
            return -EINVAL;
        } 
        ret = ops->pin_config_group_set(pctldev,   //调用pin_config_group_set函数, 芯片厂商实现的函数, 操作寄存器
                setting->data.configs.group_or_pin, 
                setting->data.configs.configs,
                setting->data.configs.num_configs);
        if (ret < 0) {
            dev_err(pctldev->dev,
                "pin_config_group_set op failed for group %d\n",
                setting->data.configs.group_or_pin);
            return ret;
        }
        break;
    default:
        return -EINVAL;
    }

    return 0;
}

//--------总结pinctrl_select_state------
- 找到pinctrl_setting根据类型调用相应的自定义的函数
- 若PIN_MAP_TYPE_MUX_GROUP调用pinmux_ops的set_mux
- 若PIN_MAP_TYPE_CONFIGS_PIN调用pinconf_ops的pin_config_set
- 若PIN_MAP_TYPE_CONFIGS_GROUP调用pinconf_ops的pin_config_group_set


```

怎么用


框架提供了消费者接口, 三步

```
struct pinctrl *devm_pinctrl_get(struct device *dev);
struct pinctrl_state *pinctrl_lookup_state(struct pinctrl *p, const char *name);
int pinctrl_select_state(struct pinctrl *p, struct pinctrl_state *state);
```
若是平台设备驱动,在设备树中配置好不需要调用, 因为设备树的节点在转化平台设备和驱动匹配成功后就调用,这个函数pinctrl_bind_pins, 以下是源码
```
int pinctrl_bind_pins(struct device *dev)
{
    int ret;

    if (dev->of_node_reused)
        return 0;

    dev->pins = devm_kzalloc(dev, sizeof(*(dev->pins)), GFP_KERNEL);
    if (!dev->pins)
        return -ENOMEM;

    dev->pins->p = devm_pinctrl_get(dev);
    if (IS_ERR(dev->pins->p)) {
        dev_dbg(dev, "no pinctrl handle\n");
        ret = PTR_ERR(dev->pins->p);
        goto cleanup_alloc;
    }

    dev->pins->default_state = pinctrl_lookup_state(dev->pins->p,
                    PINCTRL_STATE_DEFAULT);
    if (IS_ERR(dev->pins->default_state)) {
        dev_dbg(dev, "no default pinctrl state\n");
        ret = 0;
        goto cleanup_get;
    }

    dev->pins->init_state = pinctrl_lookup_state(dev->pins->p,
                    PINCTRL_STATE_INIT);
    if (IS_ERR(dev->pins->init_state)) {
        /* Not supplying this state is perfectly legal */
        dev_dbg(dev, "no init pinctrl state\n");

        ret = pinctrl_select_state(dev->pins->p,
                       dev->pins->default_state);
    } else {
        ret = pinctrl_select_state(dev->pins->p, dev->pins->init_state);
    }

    if (ret) {
        dev_dbg(dev, "failed to activate initial pinctrl state\n");
        goto cleanup_get;
    }

#ifdef CONFIG_PM
    /*
     * If power management is enabled, we also look for the optional
     * sleep and idle pin states, with semantics as defined in
     * <linux/pinctrl/pinctrl-state.h>
     */
    dev->pins->sleep_state = pinctrl_lookup_state(dev->pins->p,
                    PINCTRL_STATE_SLEEP);
    if (IS_ERR(dev->pins->sleep_state))
        /* Not supplying this state is perfectly legal */
        dev_dbg(dev, "no sleep pinctrl state\n");

    dev->pins->idle_state = pinctrl_lookup_state(dev->pins->p,
                    PINCTRL_STATE_IDLE);
    if (IS_ERR(dev->pins->idle_state))
        /* Not supplying this state is perfectly legal */
        dev_dbg(dev, "no idle pinctrl state\n");
#endif

    return 0;

    /*
     * If no pinctrl handle or default state was found for this device,
     * let's explicitly free the pin container in the device, there is
     * no point in keeping it around.
     */
cleanup_get:
    devm_pinctrl_put(dev->pins->p);
cleanup_alloc:
    devm_kfree(dev, dev->pins);
    dev->pins = NULL;

    /* Return deferrals */
    if (ret == -EPROBE_DEFER)
        return ret;
    /* Return serious errors */
    if (ret == -EINVAL)
        return ret;
    /* We ignore errors like -ENOENT meaning no pinctrl state */

    return 0;
}

    
```

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值