pinctrl子系统分析(二)

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主要分三个步骤:

  1. 获得设备的pin control state holder;
  2. 调用pinctrl_lookup_state函数查找设备的pin control state;
  3. 调用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;

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值