pinctrl子系统 - 源码解析(五)

一,pincontroller (pinctrl server)构造

1,pin controller driver与 device match并执行probe
diwali_pinctrl_init
    platform_driver_register(&diwali_pinctrl_driver); //根据match table找到device
        diwali_pinctrl_probe
            pinctrl_data = of_device_get_match_data(&pdev->dev);//获取msm_pinctrl_soc_data
            msm_pinctrl_probe(pdev, pinctrl_data);//传递soc data
2,probe流程
int msm_pinctrl_probe(struct platform_device *pdev,
              const struct msm_pinctrl_soc_data *soc_data)
{
    // 1)分配一个msm_pinctrl结构并初始化
    msm_pinctrl_data = pctrl = devm_kzalloc(&pdev->dev, sizeof(*pctrl), GFP_KERNEL);
    if (!pctrl)
        return -ENOMEM;

    pctrl->dev = &pdev->dev;
    pctrl->soc = soc_data;
    pctrl->chip = msm_gpio_template;
    pctrl->intr_target_use_scm = of_device_is_compatible(
                    pctrl->dev->of_node,
                    "qcom,ipq8064-pinctrl");
    
    // 2)从pin controller device dts节点中获取设备的物理地址
    res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
    if (!res)
        return -ENOENT;
    //将设备的物理地址转换为虚拟地址,使用该地址读写该pin controller device
    pctrl->regs[0] = devm_ioremap_resource(&pdev->dev, res);
    if (IS_ERR(pctrl->regs[0]))
        return PTR_ERR(pctrl->regs[0]);

    pctrl->phys_base[0] = res->start;

    //3)从pin controller device dts节点中获取irq number
    pctrl->irq = platform_get_irq(pdev, 0);
    if (pctrl->irq < 0)
        return pctrl->irq;

    //4) 构造一个pinctrl_desc
    pctrl->desc.owner = THIS_MODULE;
    //引脚枚举与命名
    pctrl->desc.pctlops = &msm_pinctrl_ops;
    //引脚复用
    pctrl->desc.pmxops = &msm_pinmux_ops;
    //引脚配置
    pctrl->desc.confops = &msm_pinconf_ops;
    pctrl->desc.name = dev_name(&pdev->dev);
    //soc data提供
    pctrl->desc.pins = pctrl->soc->pins;
    pctrl->desc.npins = pctrl->soc->npins;
    pctrl->desc.num_custom_params = ARRAY_SIZE(msm_gpio_bindings);
    pctrl->desc.custom_params = msm_gpio_bindings;

    //根据pinctrl_desc信息构造一个pinctrl_dev
    pctrl->pctrl = devm_pinctrl_register(&pdev->dev, &pctrl->desc, pctrl);
    if (IS_ERR(pctrl->pctrl)) {
        dev_err(&pdev->dev, "Couldn't register pinctrl driver\n");
        return PTR_ERR(pctrl->pctrl);
    }

    //5)
    ret = msm_gpio_init(pctrl);
    if (ret)
        return ret;

    platform_set_drvdata(pdev, pctrl);
}

pin controller描述符中包括了三类操作函数:pctlops是一些全局的控制函数,pmxops是复用引脚相关的操作函数,confops操作函数是用来配置引脚的特性(例如:pull-up/down)。这些callback函数都是和具体的底层pin controller的操作相关,qcom平台pinctrl controller low level driver实现的API如下,每一个的实现请查看kernel开源代码pinctrl-msm.c:

1)struct pinctrl_ops

static const struct pinctrl_ops msm_pinctrl_ops = {
    .get_groups_count    = msm_get_groups_count,
    .get_group_name        = msm_get_group_name,
    .get_group_pins        = msm_get_group_pins,
    .dt_node_to_map        = pinconf_generic_dt_node_to_map_group,
    .dt_free_map        = pinctrl_utils_free_map,
};

2)struct pinmux_ops

static const struct pinmux_ops msm_pinmux_ops = {
    .request        = msm_pinmux_request,
    .get_functions_count    = msm_get_functions_count,
    .get_function_name    = msm_get_function_name,
    .get_function_groups    = msm_get_function_groups,
    .gpio_request_enable    = msm_pinmux_request_gpio,
    .set_mux        = msm_pinmux_set_mux,
};

3)struct pinconf_ops

static const struct pinconf_ops msm_pinconf_ops = {
    .is_generic        = true,
    .pin_config_group_get    = msm_config_group_get,
    .pin_config_group_set    = msm_config_group_set,
};
3,devm_pinctrl_register()流程
pctrl->pctrl = devm_pinctrl_register(&pdev->dev, &pctrl->desc, pctrl);
    pctldev = pinctrl_register(pctldesc, dev, driver_data);
        pinctrl_init_controller(pctldesc, dev, driver_data);
            //给pinctrl_dev分配内存
            pctldev = kzalloc(sizeof(*pctldev), GFP_KERNEL);
            // driver_data是msm_pinctrl
            pctldev->driver_data = driver_data;
            //check core ops for sanity
            pinctrl_check_ops(pctldev);
            //If we're implementing pinmuxing, check the ops for sanity
            pinmux_check_ops(pctldev);
            //If we're implementing pinconfig, check the ops for sanity
            pinconf_check_ops(pctldev);
            pinctrl_register_pins(pctldev, pctldesc->pins, pctldesc->npins);
        pinctrl_enable(pctldev);
            //将pinctrl_dev加入pinctrldev_list链表
            list_add_tail(&pctldev->node, &pinctrldev_list);
            //在每一个pin controller device的目录中生成pinctrl调试节点,eg:/sys/kernel/debug/pinctrl/f000000.pinctrl
            pinctrl_init_device_debugfs(pctldev);
                debugfs_create_file("pins", S_IFREG | S_IRUGO, device_root, pctldev, &pinctrl_pins_fops);
                debugfs_create_file("pingroups", S_IFREG | S_IRUGO, device_root, pctldev, &pinctrl_groups_fops);
                debugfs_create_file("gpio-ranges", S_IFREG | S_IRUGO, device_root, pctldev, &pinctrl_gpioranges_fops);

二,client端使用pinctrl的过程

1,dev_pin_info

设备节点要么被转换为platform_device,或者其他结构体(比如i2c_client),但是里面都会有一个device结构体,每个device结构体里都有一个dev_pin_info结构体,用来保存设备的pinctrl信息。

platform_device匹配driver会执行probe探测函数,执行到驱动中真正的probe函数之前,会进行pinctrl的处理,处理函数为pinctrl_bind_pins。

really_probe()
    pinctrl_bind_pins(dev);
        devm_pinctrl_get(dev);
            pinctrl_get(dev);
                create_pinctrl(dev, NULL);
                    //把dts中该设备的pinctrl配置解析到pinctrl map中
                    pinctrl_dt_to_map(p, pctldev);
                        dt_to_map_one_config(p, pctldev, statename, np_config);
                            ops->dt_node_to_map(pctldev, np_config, &map, &num_maps);
                                .dt_node_to_map        = pinconf_generic_dt_node_to_map_group,
                                    pinconf_generic_dt_node_to_map
                                        //pinctrl map mux
                                        pinctrl_utils_add_map_mux
                                        //pinctrl map configs
                                        pinctrl_utils_add_map_configs
                    
                    //把pinctrl map 转为pinctrl setting
                    add_setting(p, pctldev, map);
                        pinmux_map_to_setting(map, setting);
                        pinconf_map_to_setting(map, setting);
                        list_add_tail(&setting->node, &state->settings);
                    
                    //该设备的pinctrl state holder挂到pinctrl_list链表
                    list_add_tail(&p->node, &pinctrl_list);
            
            //解析标准的pinctrl state,PINCTRL_STATE_DEFAULT/PINCTRL_STATE_INIT/PINCTRL_STATE_SLEEP/PINCTRL_STATE_IDLE
            dev->pins->default_state = pinctrl_lookup_state(dev->pins->p, PINCTRL_STATE_DEFAULT);
            dev->pins->init_state = pinctrl_lookup_state(dev->pins->p, PINCTRL_STATE_INIT);
            pinctrl_select_state(dev->pins->p, dev->pins->default_state);

            dev->pins->sleep_state = pinctrl_lookup_state(dev->pins->p, PINCTRL_STATE_SLEEP);
            dev->pins->idle_state = pinctrl_lookup_state(dev->pins->p, PINCTRL_STATE_IDLE);

//执行device或者driver的probe函数
dev->bus->probe(dev);
drv->probe(dev);
2,pinctrl debugfs
2.1 一个pin controller device --- f000000.pinctrl
ls -l /sys/kernel/debug/pinctrl/f000000.pinctrl
-r--r--r-- 1 root root 0 1970-01-01 00:00 gpio-ranges
-r--r--r-- 1 root root 0 1970-01-01 00:00 pinconf-groups
-r--r--r-- 1 root root 0 1970-01-01 00:00 pinconf-pins
-r--r--r-- 1 root root 0 1970-01-01 00:00 pingroups
-r--r--r-- 1 root root 0 1970-01-01 00:00 pinmux-functions
-r--r--r-- 1 root root 0 1970-01-01 00:00 pinmux-pins
-r--r--r-- 1 root root 0 1970-01-01 00:00 pins

系统中注册的所有的pinctrl controller,打印接口:

static int pinctrl_devices_show(struct seq_file *s, void *what)
{
    struct pinctrl_dev *pctldev;

    seq_puts(s, "name [pinmux] [pinconf]\n");

    mutex_lock(&pinctrldev_list_mutex);

    list_for_each_entry(pctldev, &pinctrldev_list, node) {
        seq_printf(s, "%s ", pctldev->desc->name);
        if (pctldev->desc->pmxops)
            seq_puts(s, "yes ");
        else
            seq_puts(s, "no ");
        if (pctldev->desc->confops)
            seq_puts(s, "yes");
        else
            seq_puts(s, "no");
        seq_puts(s, "\n");
    }

    mutex_unlock(&pinctrldev_list_mutex);

    return 0;
}
DEFINE_SHOW_ATTRIBUTE(pinctrl_devices);

cat /sys/kernel/debug/pinctrl/pinctrl-devices:

name [pinmux] [pinconf]
f000000.pinctrl yes yes
c42d000.qcom,spmi:qcom,pmk8350@0:pinctrl@b000 yes yes
c42d000.qcom,spmi:qcom,pm8350c@2:pinctrl@8800 yes yes
c42d000.qcom,spmi:qcom,pm7325@1:pinctrl@8800 yes yes
c42d000.qcom,spmi:qcom,pm8350b@3:pinctrl@8800 yes yes
soc:spf_core_platform:lpi_pinctrl@3440000 yes yes
2.2 pinctrl maps信息打印接口
static int pinctrl_maps_show(struct seq_file *s, void *what)
{
    struct pinctrl_maps *maps_node;
    int i;
    const struct pinctrl_map *map;

    seq_puts(s, "Pinctrl maps:\n");

    mutex_lock(&pinctrl_maps_mutex);
    for_each_maps(maps_node, i, map) {
        seq_printf(s, "device %s\nstate %s\ntype %s (%d)\n",
               map->dev_name, map->name, map_type(map->type),
               map->type);

        if (map->type != PIN_MAP_TYPE_DUMMY_STATE)
            seq_printf(s, "controlling device %s\n",
                   map->ctrl_dev_name);

        switch (map->type) {
        case PIN_MAP_TYPE_MUX_GROUP:
            pinmux_show_map(s, map);
            break;
        case PIN_MAP_TYPE_CONFIGS_PIN:
        case PIN_MAP_TYPE_CONFIGS_GROUP:
            pinconf_show_map(s, map);
            break;
        default:
            break;
        }

        seq_putc(s, '\n');
    }
    mutex_unlock(&pinctrl_maps_mutex);

    return 0;
}
DEFINE_SHOW_ATTRIBUTE(pinctrl_maps);

pinctrl client 节点举例:

//一个device的pinctrl state配置
xxx@xx {
    pinctrl-names = "pmx_ts_active", "pmx_ts_suspend", "pmx_ts_release";
    pinctrl-0 = <&ts_active>;
    pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>;                    
    pinctrl-2 = <&ts_release>;    
};

pinctrl server 端的配置见上一篇文章,解析后的pinctrl maps信息:

cat /sys/kernel/debug/pinctrl/pinctrl-maps

device spi1.0
state pmx_ts_active
type MUX_GROUP (2)
controlling device f000000.pinctrl
group gpio129
function gpio


device spi1.0
state pmx_ts_active
type MUX_GROUP (2)
controlling device f000000.pinctrl
group gpio51
function gpio


device spi1.0
state pmx_ts_active
type CONFIGS_GROUP (4)
controlling device f000000.pinctrl
group gpio129
config 00000105
config 00000809


device spi1.0
state pmx_ts_active
type CONFIGS_GROUP (4)
controlling device f000000.pinctrl
group gpio51
config 00000105
config 00000809


device spi1.0
state pmx_ts_suspend
type MUX_GROUP (2)
controlling device f000000.pinctrl
group gpio51
function gpio


device spi1.0
state pmx_ts_suspend
type CONFIGS_GROUP (4)
controlling device f000000.pinctrl
group gpio51
config 00000103
config 00000209


device spi1.0
state pmx_ts_suspend
type MUX_GROUP (2)
controlling device f000000.pinctrl
group gpio129
function gpio


device spi1.0
state pmx_ts_suspend
type CONFIGS_GROUP (4)
controlling device f000000.pinctrl
group gpio129
config 00000103
config 00000209


device spi1.0
state pmx_ts_release
type MUX_GROUP (2)
controlling device f000000.pinctrl
group gpio129
function gpio


device spi1.0
state pmx_ts_release
type MUX_GROUP (2)
controlling device f000000.pinctrl
group gpio51
function gpio


device spi1.0
state pmx_ts_release
type CONFIGS_GROUP (4)
controlling device f000000.pinctrl
group gpio129
config 00000001
config 00000209


device spi1.0
state pmx_ts_release
type CONFIGS_GROUP (4)
controlling device f000000.pinctrl
group gpio51
config 00000001
config 00000209
2.3 pinctrl setting信息打印接口
static int pinctrl_show(struct seq_file *s, void *what)
{
    struct pinctrl *p;
    struct pinctrl_state *state;
    struct pinctrl_setting *setting;

    seq_puts(s, "Requested pin control handlers their pinmux maps:\n");

    mutex_lock(&pinctrl_list_mutex);

    list_for_each_entry(p, &pinctrl_list, node) {
        seq_printf(s, "device: %s current state: %s\n",
               dev_name(p->dev),
               p->state ? p->state->name : "none");

        list_for_each_entry(state, &p->states, node) {
            seq_printf(s, "  state: %s\n", state->name);

            list_for_each_entry(setting, &state->settings, node) {
                struct pinctrl_dev *pctldev = setting->pctldev;

                seq_printf(s, "    type: %s controller %s ",
                       map_type(setting->type),
                       pinctrl_dev_get_name(pctldev));

                switch (setting->type) {
                case PIN_MAP_TYPE_MUX_GROUP:
                    pinmux_show_setting(s, setting);
                    break;
                case PIN_MAP_TYPE_CONFIGS_PIN:
                case PIN_MAP_TYPE_CONFIGS_GROUP:
                    pinconf_show_setting(s, setting);
                    break;
                default:
                    break;
                }
            }
        }
    }

    mutex_unlock(&pinctrl_list_mutex);

    return 0;
}
DEFINE_SHOW_ATTRIBUTE(pinctrl);

上一节pinctrl maps转成的pinctrl settings信息打印:

cat /sys/kernel/debug/pinctrl/pinctrl-handles

device: spi1.0 current state: pmx_ts_active

  state: pmx_ts_active
    type: MUX_GROUP controller f000000.pinctrl group: gpio129 (129) function: gpio (0)
    type: MUX_GROUP controller f000000.pinctrl group: gpio51 (51) function: gpio (0)
    type: CONFIGS_GROUP controller f000000.pinctrl group gpio129 (129)config 00000105
config 00000809
    type: CONFIGS_GROUP controller f000000.pinctrl group gpio51 (51)config 00000105
config 00000809

  state: pmx_ts_suspend
    type: MUX_GROUP controller f000000.pinctrl group: gpio51 (51) function: gpio (0)
    type: CONFIGS_GROUP controller f000000.pinctrl group gpio51 (51)config 00000103
config 00000209
    type: MUX_GROUP controller f000000.pinctrl group: gpio129 (129) function: gpio (0)
    type: CONFIGS_GROUP controller f000000.pinctrl group gpio129 (129)config 00000103
config 00000209

  state: pmx_ts_release
    type: MUX_GROUP controller f000000.pinctrl group: gpio129 (129) function: gpio (0)
    type: MUX_GROUP controller f000000.pinctrl group: gpio51 (51) function: gpio (0)
    type: CONFIGS_GROUP controller f000000.pinctrl group gpio129 (129)config 00000001
config 00000209
    type: CONFIGS_GROUP controller f000000.pinctrl group gpio51 (51)config 00000001
config 00000209
3,设备树节点转换为pinctrl_map

pinctrl_dt_to_map:

int pinctrl_dt_to_map(struct pinctrl *p, struct pinctrl_dev *pctldev)
{
    struct device_node *np = p->dev->of_node;
    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 */
    //遍历所有的state ID
    for (state = 0; ; state++) {
        /* Retrieve the pinctrl-* property */
        propname = kasprintf(GFP_KERNEL, "pinctrl-%d", state);
        if (!propname)
            return -ENOMEM;
        prop = of_find_property(np, propname, &size);
        kfree(propname);
        if (!prop) {
            if (state == 0) {
                of_node_put(np);
                return -ENODEV;
            }
            break;
        }
        list = prop->value;
        //一个state对应的config的数量
        size /= sizeof(*list);

        /* Determine whether pinctrl-names property names the state */
        //从pinctrl-names中获取statename
        ret = of_property_read_string_index(np, "pinctrl-names",
                            state, &statename);
        /*
         * 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 */
        //遍历每一个state下面的每一个config
        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 */
            //对于一个config节点的解析函数
            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 (;;) {
        //找到pctldev
        pctldev = get_pinctrl_dev_from_of_node(np_pctldev);
    }
    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;
    }

    //调用pinctrl driver中实现的dt_node_to_map
    ret = ops->dt_node_to_map(pctldev, np_config, &map, &num_maps);

    /* Stash the mapping table chunk away for later use */
    //保存解析出来的pinctrl maps
    return dt_remember_or_free_map(p, statename, pctldev, map, num_maps);
}

保存解析出来的pinctrl maps,pinctrldt_remember_or_free_map:

dt_remember_or_free_map
    list_add_tail(&dt_map->node, &p->dt_maps);
    pinctrl_register_mappings(map, num_maps);
        list_add_tail(&maps_node->node, &pinctrl_maps);
4,pinctrl map to pinctrl setting流程
 mutex_lock(&pinctrl_maps_mutex);
    /* Iterate over the pin control maps to locate the right ones */
    //取出pinctrl_maps链表中的每一个node,遍历每一个node中的&_maps_node_->maps[_i_] (指向struct pinctrl_map的map指针)
    for_each_maps(maps_node, i, 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;

        //一个map转为一个setting
        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);

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;

    //首先在struct pinctrl结构体中查找该state是否存在,list_for_each_entry(state, &p->states, node)
    state = find_state(p, map->name);
    if (!state)
        //如果state不存在就新建一个state,list_add_tail(&state->node, &p->states);
        state = create_state(p, map->name);
    if (IS_ERR(state))
        return PTR_ERR(state);

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

    //给struct pinctrl_setting分配内存空间
    setting = kzalloc(sizeof(*setting), GFP_KERNEL);
    if (!setting)
        return -ENOMEM;
    
    //初始化setting结构体
    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:
        //pinmux map to setting
        ret = pinmux_map_to_setting(map, setting);
        break;
    case PIN_MAP_TYPE_CONFIGS_PIN:
    case PIN_MAP_TYPE_CONFIGS_GROUP:
        //pin configure map to setting
        ret = pinconf_map_to_setting(map, setting);
        break;
    default:
        ret = -EINVAL;
        break;
    }
    if (ret < 0) {
        kfree(setting);
        return ret;
    }

    //将转化后的setting挂到state->settings链表
    list_add_tail(&setting->node, &state->settings);

    return 0;
}

pinmux_map_to_setting:

int pinmux_map_to_setting(const struct pinctrl_map *map,
              struct pinctrl_setting *setting)
{
    struct pinctrl_dev *pctldev = setting->pctldev;
    const struct pinmux_ops *pmxops = pctldev->desc->pmxops;
    char const * const *groups;
    unsigned num_groups;
    int ret;
        
    ret = pinmux_func_name_to_selector(pctldev, map->data.mux.function);
    setting->data.mux.func = ret;

    
    ret = pmxops->get_function_groups(pctldev, setting->data.mux.func,
                      &groups, &num_groups);
    if (ret < 0) {
        dev_err(pctldev->dev, "can't query groups for function %s\n",
            map->data.mux.function);
        return ret;
    }

    ret = pinctrl_get_group_selector(pctldev, group);
    if (ret < 0) {
        dev_err(pctldev->dev, "invalid group %s in map table\n",
            map->data.mux.group);
        return ret;
    }
    setting->data.mux.group = ret;

    return 0;
}

map 到 setting的转化只是将字符串转为整型数表示的形式。

5,client节点如何使用设置管脚
really_probe
    pinctrl_bind_pins
        /* 寻找state */
        pinctrl_lookup_state
        /* 选择state */
        pinctrl_select_state
            pinctrl_commit_state
                /* 遍历settings链表 */
                list_for_each_entry(setting, &state->settings, node) {
                    switch (setting->type) {
                        case PIN_MAP_TYPE_MUX_GROUP:
                            /* 设置复用 */
                               pinmux_enable_setting(setting);
                                ops->set_mux(...);
                        case PIN_MAP_TYPE_CONFIGS_PIN:
                        case PIN_MAP_TYPE_CONFIGS_GROUP:
                            /* 设置配置 */
                            pinconf_apply_setting(setting);
                                ops->pin_config_group_set(...);
               }

参考链接:

pinctrl 子系统介绍_pinctrl子系统_kenny_wju的博客-CSDN博客

Linux内核中的GPIO系统之(3):pin controller driver代码分析

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值