kernel - pinctrl (二)

一、数据结构

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_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接口

  • 在设备与驱动匹配的过程中会调用到__device_attach_driver或者__driver_attach函数,这二者都会去调用driver_probe_device函数
int driver_probe_device(struct device_driver *drv, struct device *dev)                                                                                          
{
    ......                                                                                                                   

    pm_runtime_barrier(dev);            
    ret = really_probe(dev, drv);       
    pm_request_idle(dev);

    .....
}

  • 该函数会继续调用really_probe进行设备与驱动的匹配工作
static int really_probe(struct device *dev, struct device_driver *drv) {
    ......
    /* If using pinctrl, bind pins now before probing */
    ret = pinctrl_bind_pins(dev);
    if (ret)
        goto pinctrl_bind_failed;
    ......
}
  • really_probe会调用pinctrl_bind_pins进行Pinctrl的配置
/**
 * pinctrl_bind_pins() - called by the device core before probe
 * @dev: the device that is just about to probe
 */
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); // 接口1
    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, // 接口2
                    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); // 接口3
    }

    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;
}
  • 调用devm_pinctrl_get获取pinctrl句柄,devm_pinctrl_get实际调用pinctrl_get
  • 调用pinctrl_lookup_state查询所需的pinctrl_state
  • 调用pinctrl_select_state设置对应管脚状态
  • 首先获取default_state、init_state,并先优配置管脚为init_state,如果init_state不存在则配置为default_state
  • 如果有电源管理配置,则获取sleep_state、idle_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
posted @ 2019-05-30 11:09  qzhang1535  阅读(893)  评论(0编辑  收藏  举报