pinctrl子系统分析(一)
pinctrl子系统分析(二)
pinctrl子系统分析(三)
pin控制器驱动
pin控制器驱动的主要工作是,枚举pin控制器的信息,如控制器有多少个引脚,支持多少个function,每个function对应几个group,支持多少个group等,建立table保存这些信息,最后调用pin control核心提供的pinctrl_register函数将pin控制器注册进系统。
pinctrl_register函数定义如下:
struct pinctrl_dev *pinctrl_register(struct pinctrl_desc *pctldesc,
struct device *dev, void *driver_data)
{
struct pinctrl_dev *pctldev;
int ret;
......
//分配一个pinctrl_dev
pctldev = kzalloc(sizeof(*pctldev), GFP_KERNEL);
if (pctldev == NULL) {
dev_err(dev, "failed to alloc struct pinctrl_dev\n");
return ERR_PTR(-ENOMEM);
}
/* 初始化pinctrl_dev */
pctldev->owner = pctldesc->owner;
pctldev->desc = pctldesc;
pctldev->driver_data = driver_data;
INIT_RADIX_TREE(&pctldev->pin_desc_tree, GFP_KERNEL);
INIT_LIST_HEAD(&pctldev->gpio_ranges);
pctldev->dev = dev;
mutex_init(&pctldev->mutex);
......
/* 注册pin */
ret = pinctrl_register_pins(pctldev, pctldesc->pins, pctldesc->npins);
......
mutex_lock(&pinctrldev_list_mutex);
//把pinctrl_dev插入全局链表pinctrldev_list
list_add_tail(&pctldev->node, &pinctrldev_list);
mutex_unlock(&pinctrldev_list_mutex);
.....
}
注册pin控制器所有的pin:
static int pinctrl_register_pins(struct pinctrl_dev *pctldev,
struct pinctrl_pin_desc const *pins,
unsigned num_descs)
{
unsigned i;
int ret = 0;
/* pinctrl_pin_desc结构体描述的引脚信息是硬件平台提供的,只包含pin号、引脚的name等
基本信息,利用这些信息为每个引脚注册一个pin_desc, pin_desc保存在pinctrl_dev的
radix tree里,方便以后查询使用
*/
for (i = 0; i < num_descs; i++) {
ret = pinctrl_register_one_pin(pctldev, &pins[i]);
if (ret)
return ret;
}
return 0;
}
static int pinctrl_register_one_pin(struct pinctrl_dev *pctldev,
const struct pinctrl_pin_desc *pin)
{
struct pin_desc *pindesc;
//分配一个pin_desc
pindesc = kzalloc(sizeof(*pindesc), GFP_KERNEL);
......
//通过pinctrl_pin_desc初始化pin_desc
pindesc->pctldev = pctldev;
if (pin->name) {
pindesc->name = pin->name;
} else {
pindesc->name = kasprintf(GFP_KERNEL, "PIN%u", pin->number);
......
pindesc->dynamic_name = true;
}
pindesc->drv_data = pin->drv_data;
//插入pinctrl_dev的radix tree,键值为pin号
radix_tree_insert(&pctldev->pin_desc_tree, pin->number, pindesc);
......
}
设置设备的pin control state
前面提到过,设备可能有多种状态,不同状态下对应的pin control state可能有所不同,而每种状态的引脚配置由一个或多个设备节点来描述。
设置设备的pin control state主要分三个步骤:
- 获得设备的pin control state holder;
- 调用pinctrl_lookup_state函数查找设备的pin control state;
- 调用pinctrl_select_state函数设置pin control state。
获得设备的pin control state holder
pin control state holder作为管理者,管理这设备的pin control state,想要设置pin control state,首先得获得holder。
调用pinctrl_get函数获取设备的pinctrl:
struct pinctrl *pinctrl_get(struct device *dev)
{
struct pinctrl *p;
......
//在全局链表pinctrl_list上找设备的pinctrl则返回
p = find_pinctrl(dev);
if (p != NULL) {
......
return p;
}
//如果在全局链表pinctrl_list上找不到的话,则为设备创建一个pinctrl
return create_pinctrl(dev);
}
初次调用pinctrl_get函数,设备是没有pinctrl的,会自动创建,通过create_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;
//分配一个pinctrl
p = kzalloc(sizeof(*p), GFP_KERNEL);
//初始化pinctrl
p->dev = dev;
INIT_LIST_HEAD(&p->states);
INIT_LIST_HEAD(&p->dt_maps);
/*
这部分内容先略过,下一章专门讲解配置节点的解析,以及pinctrl_setting的初始化
ret = pinctrl_dt_to_map(p);
mutex_lock(&pinctrl_maps_mutex);
for_each_maps(maps_node, i, map) {
if (strcmp(map->dev_name, devname))
continue;
ret = add_setting(p, map);
......
}
mutex_unlock(&pinctrl_maps_mutex);
*/
......
mutex_lock(&pinctrl_list_mutex);
list_add_tail(&p->node, &pinctrl_list); //把pinctrl插入全局链表pinctrl_list
mutex_unlock(&pinctrl_list_mutex);
return p;
}
查找设备的所拥有的pin control state
//name指向状态的名字
struct pinctrl_state *pinctrl_lookup_state(struct pinctrl *p,
const char *name)
{
struct pinctrl_state *state;
//在pinctrl的states链表查找是否有指定的pinctrl_state
state = find_state(p, name);
if (!state) {
......
//没有则创建
state = create_state(p, name);
} else
state = ERR_PTR(-ENODEV);
}
return state;
}
static struct pinctrl_state *create_state(struct pinctrl *p,
const char *name)
{
struct pinctrl_state *state;
//分配一个pinctrl_state
state = kzalloc(sizeof(*state), GFP_KERNEL);
......
//设置pinctrl_state的name
state->name = name;
INIT_LIST_HEAD(&state->settings);
//插入pinctrl的state链表
list_add_tail(&state->node, &p->states);
return state;
}
为了理清楚pinctrl与pinctrl_state的关系,我画了下面这张图:
pinctrl_state对应设备一种状态下的pin control state,其有一个settings链表,用于链接一个或多个pinctrl_setting,pinctrl_setting结构体定义如下:
struct pinctrl_setting {
//用于链入pinctrl_state
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; //用于配置引脚的配置信息
};
通过pinctrl_setting,可以设置设备在某种状态下的引脚配置,毫无疑问,这些pinctrl_setting是通过配置节点描述的配置信息来初始化的。
调用pinctrl_select_state函数设置pin control 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;
//当前已处于要设置的pin control state,则不需要设置了,直接返回
if (p->state == state)
return 0;
......
p->state = NULL;
/* 遍历pinctrl_state的settings链表取出每个pinctrl_setting
根据pinctrl_setting的类型进行不同的配置
*/
list_for_each_entry(setting, &state->settings, node) {
switch (setting->type) {
case PIN_MAP_TYPE_MUX_GROUP:
ret = pinmux_enable_setting(setting); //最终调用pinmux_ops->set_mux进行设置
break;
case PIN_MAP_TYPE_CONFIGS_PIN:
case PIN_MAP_TYPE_CONFIGS_GROUP:
/* 对于PIN_MAP_TYPE_CONFIGS_PIN,最终调用pinconf_ops->pin_config_set设置
对于PIN_MAP_TYPE_CONFIGS_GROUP,最终调用pinconf_ops->pin_config_group_set设置
*/
ret = pinconf_apply_setting(setting);
break;
......
}
p->state = state;
return 0;
......
}