linux pinctrl驱动分析

linux pinctrl驱动分析 altas200模块

  • 准备
  • 设备树节点
  • pinctrl驱动分析
    • pcs_probe函数
      • pcs_allocate_pin_table函数
      • pcs_add_pin函数
      • pinctrl_register_one_pin函数
      • pinctrl_enable函数
      • pinctrl_claim_hogs函数
  • 总结
    • 主要结构体
      • pcs_device
      • pinctrl_desc
      • pinctrl_dev
    • 总结

准备

  使用的源码包为华为官方的ascend200AI加速模块的SDK,其下载地址位于:点击跳转
  使用的固件与驱动版本为:1.0.9.alpha
  压缩包名称为:A200-3000-sdk_20.2.0.zip
  将A200-3000-sdk_20.2.0.zip解压后可以看到Ascend310-source-minirc.tar.gz压缩包,这个压缩包里有ascend200AI加速模块的linux内核源码包、设备树及驱动文件等。

设备树节点

  pinctrl的设备树节点位于source/dtb/hi1910-asic-000-pinctrl.dtsi
  这里以pmx_ctrl1节点和pmx_cfg1两个节点为例:

	pmx_ctrl1: pinmux@110080000 {
		compatible = "pinctrl-single", "pinctrl-single1";
		reg = <0x1 0x10080000 0x0 0x38>;
		#gpio-range-cells = <3>;
		pinctrl-single,register-width = <32>;
		pinctrl-single,function-mask = <7>;	
		
		gpio2_pmx_func: gpio2_pmx_func {
			pinctrl-single,pins = <0x2c    0x0>;
		};
		
		gpio2_pmx_idle: gpio2_pmx_idle {
 			pinctrl-single,pins = <0x2c    0x0>;
		};
		
		gpio3_pmx_func: gpio3_pmx_func {
			pinctrl-single,pins = <0x30    0x0>;
		};
		
		gpio3_pmx_idle: gpio3_pmx_idle {
 			pinctrl-single,pins = <0x30    0x0>;
		};									
	};
    pmx_cfg1: pinmux@110080800 {
		compatible = "pinconf-single", "pinctrl-single1";
		reg = <0x1 0x10080800 0x0 0x05c>;
		pinctrl-single,register-width = <32>;	
		gpio6_cfg_func: gpio6_cfg_func {
			pinctrl-single,pins = <0x28  0>;
			pinctrl-single,bias-pulldown = <0 2 0 2>;
			pinctrl-single,bias-pullup = <1 1 0 1>;	
			pinctrl-single,drive-strength = <0x30 0x70>;				
		};
		gpio6_cfg_idle: gpio6_cfg_idle {
			pinctrl-single,pins = <0x28  0>;
			pinctrl-single,bias-pulldown = <0 2 0 2>;
			pinctrl-single,bias-pullup = <1 1 0 1>;
			pinctrl-single,drive-strength = <0x30 0x70>;				
		};
				
		gpio2_cfg_func: gpio2_cfg_func {
			pinctrl-single,pins = <0x50  0>;
			pinctrl-single,bias-pulldown = <2 2 0 2>;
			pinctrl-single,bias-pullup = <0 1 0 1>;
			pinctrl-single,drive-strength = <0x30 0x70>;	
			pinctrl-single,input-schmitt-enable = <8 8 0 8>;		
		};
		gpio2_cfg_idle: gpio2_cfg_idle {
			pinctrl-single,pins = <0x50  0>;
			pinctrl-single,bias-pulldown = <2 2 0 2>;
			pinctrl-single,bias-pullup = <0 1 0 1>;
			pinctrl-single,drive-strength = <0x30 0x70>;	
			pinctrl-single,input-schmitt-enable = <8 8 0 8>;				
		};
		
		gpio3_cfg_func: gpio3_cfg_func {
			pinctrl-single,pins = <0x54  0>;
			pinctrl-single,bias-pulldown = <0 2 0 2>;
			pinctrl-single,bias-pullup = <1 1 0 1>;
			pinctrl-single,drive-strength = <0x30 0x70>;	
			pinctrl-single,input-schmitt-enable = <8 8 0 8>;		
		};
		gpio3_cfg_idle: gpio3_cfg_idle {
			pinctrl-single,pins = <0x54  0>;
			pinctrl-single,bias-pulldown = <0 2 0 2>;
			pinctrl-single,bias-pullup = <1 1 0 1>;
			pinctrl-single,drive-strength = <0x30 0x70>;	
			pinctrl-single,input-schmitt-enable = <8 8 0 8>;				
		};					
    };

pinctrl驱动分析

  设备树节点无论是pinconf-single还是pinctrl-single匹配到的都是source\kernel\linux-4.19\drivers\pinctrl\pinctrl-single.c

pcs_probe函数

static int pcs_probe(struct platform_device *pdev)
{
	struct device_node *np = pdev->dev.of_node;
	struct pcs_pdata *pdata;
	struct resource *res;
	struct pcs_device *pcs;
	const struct pcs_soc_data *soc;
	int ret;
	//of_device_get_match_data 判断dts中的compatible属性是否包含driver中指定的compatible,
	// 实际上返回的是dev->driver->of_match_table->data。
	// data是void *类型,自己如果想取到data里的值,就可以自己定义类型,里面可以放一些自己需要的参数。
	//of_device_get_match_data对于pmx_ctrl1节点,它的data为空,可以不管
	//而pmx_cfg1节点此时soc->flag=PCS_FEAT_PINCONF。让后给pcs分配内存
	//PCS_FEAT_PINCONF	(1 << 0)
	soc = of_device_get_match_data(&pdev->dev);
	if (WARN_ON(!soc))
		return -EINVAL;
	//申请pcs结构体内存,这个pdev->dev这个参数是为了绑定这片内存
	//devm_kzalloc分配的内存当指定的dev驱动被注销时会自动释放
	pcs = devm_kzalloc(&pdev->dev, sizeof(*pcs), GFP_KERNEL);
	if (!pcs)
		return -ENOMEM;
	//这个np是dtb转化的device_node
	pcs->dev = &pdev->dev;
	pcs->np = np;
	raw_spin_lock_init(&pcs->lock);
	mutex_init(&pcs->mutex);
	//初始化链表
	INIT_LIST_HEAD(&pcs->gpiofuncs);
	//pcs->flags = PCS_FEAT_PINCONF = 1
	pcs->flags = soc->flags;
	//之后pcs->socdata指向soc结构体
	memcpy(&pcs->socdata, soc, sizeof(*soc));
	//获取"pinctrl-single,register-width"属性,好像是寄存器的位宽,都是32位的
	ret = of_property_read_u32(np, "pinctrl-single,register-width",
				   &pcs->width);
	if (ret) {
		dev_err(pcs->dev, "register width not specified\n");

		return ret;
	}
	//pcs->fmask是7
	ret = of_property_read_u32(np, "pinctrl-single,function-mask",
				   &pcs->fmask);
	if (!ret) {
	//存在属性,所以指向下面的代码
	//__ffs 用于找到一个int或者long行最高哪位是1,例如0x8000,就会返回15.
	//pcs->fshift 为2   pcs->fmax为1
		pcs->fshift = __ffs(pcs->fmask);
		pcs->fmax = pcs->fmask >> pcs->fshift;
	} else {
		/* If mask property doesn't exist, function mux is invalid. */
		pcs->fmask = 0;
		pcs->fshift = 0;
		pcs->fmax = 0;
	}
	//这个属性没有
	ret = of_property_read_u32(np, "pinctrl-single,function-off",
					&pcs->foff);
	if (ret)
		pcs->foff = PCS_OFF_DISABLED;
	//这个没有读到 也是0
	pcs->bits_per_mux = of_property_read_bool(np,
						  "pinctrl-single,bit-per-mux");
	//pcs->bits_per_mux ? 2 : 1 为1
	//这个函数是老版的函数要找"#pinctrl-cells"属性,没有 直接返回0
	ret = pcs_quirk_missing_pinctrl_cells(pcs, np,
					      pcs->bits_per_mux ? 2 : 1);
	if (ret) {
		dev_err(&pdev->dev, "unable to patch #pinctrl-cells\n");

		return ret;
	}
	//获取IORESOURCE_MEM资源,即reg属性
	//pmx_ctrl1节点reg = <0x1 0x10080000 0x0 0x38>;
	//pmx_cfg1节点为reg = <0x1 0x10080800 0x0 0x05c>;
	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	if (!res) {
		dev_err(pcs->dev, "could not get resource\n");
		return -ENODEV;
	}
	//节点pmx_ctrl1
	//res->start:268959744 ----- res->end:268959799
	//resource_size:56

	//节点pmx_cfg1
	//res->start:268961792 ----- res->end:268961883
	//resource_size:92
	//devm_request_mem_region将res的物理空间iormmap映射出来,返回给pcs->res,能通过用户空间操作
	pcs->res = devm_request_mem_region(pcs->dev, res->start,
			resource_size(res), DRIVER_NAME);
	if (!pcs->res) {
		dev_err(pcs->dev, "could not get mem_region\n");
		return -EBUSY;
	}
	//这里的pcs的size和base就是映射出来的大小和基址
	pcs->size = resource_size(pcs->res);
	pcs->base = devm_ioremap(pcs->dev, pcs->res->start, pcs->size);
	if (!pcs->base) {
		dev_err(pcs->dev, "could not ioremap\n");
		return -ENODEV;
	}
	//pdev->device->device_data指针指向pcs,保存变量,pcs是malloc出来的内存
	platform_set_drvdata(pdev, pcs);
	//(pcs->width为32
	switch (pcs->width) {
	case 8:
		pcs->read = pcs_readb;
		pcs->write = pcs_writeb;
		break;
	case 16:
		pcs->read = pcs_readw;
		pcs->write = pcs_writew;
		break;
	case 32:
		pcs->read = pcs_readl;
		pcs->write = pcs_writel;
		break;
	default:
		break;
	}
	//DRIVER_NAME			"pinctrl-single"
	//构造pinctrl_desc结构体,desc.pctlops是引脚的操作功能,desc.pmxops是引脚复用功能
	//这两个函数是具体的硬件功能操作函数
	pcs->desc.name = DRIVER_NAME;
	pcs->desc.pctlops = &pcs_pinctrl_ops;
	pcs->desc.pmxops = &pcs_pinmux_ops;
	//pmx_cfg1:
	//PCS_HAS_PINCONF = (pcs->flags & PCS_FEAT_PINCONF)
	//PCS_FEAT_PINCONF	(1 << 0)
	//pcs->flag = PCS_FEAT_PINCONF	(1 << 0)
	//PCS_HAS_PINCONF = 1
	//注意:pmx_ctrl1节点没有flag属性,所以这个为0
	//pcs_pinconf_ops是配置功能,所以只有pmx_cfg1节点的desc有这个功能
	if (PCS_HAS_PINCONF)
		pcs->desc.confops = &pcs_pinconf_ops;
	pcs->desc.owner = THIS_MODULE;
	//这个函数啥也没干,只是设置pindesc等一些属性,主要是引脚树木等
	ret = pcs_allocate_pin_table(pcs);
	if (ret < 0)
		goto free;
	
	//pinctrl_register函数,构造pinctrl_dev结构体
	//1.传入pinctrl_desc,pctldev->desc指向传入的pinctrl_desc
	//2.申请pinctrl_dev结构体内存
	//3.初始化了pin_desc_tree、pin_group_tree、pin_function_tree三个树
	//4.检查pctldev->desc->pctlops是否有get_group_count和get_group_name函数
	//5.检查pctldev->desc->pmxops是否有必要的函数
	//6.检查pctldev->desc->confops是否有必要的函数
	//7.指向pinctrl_register_one_pin挨个注册管脚
	//8.将每个pin的pin_desc都加入到 &pcs->pctl(pinctrl_dev)管理起来
	ret = pinctrl_register_and_init(&pcs->desc, pcs->dev, pcs, &pcs->pctl);
	if (ret) {
		dev_err(pcs->dev, "could not register single pinctrl driver\n");
		goto free;
	}
	//去device_node找pinctrl-single,gpio-range和#pinctrl-single,gpio-range-cells,没有就直接返回了
	ret = pcs_add_gpio_func(np, pcs);
	if (ret < 0)
		goto free;
	//中断也没有,不用管
	pcs->socdata.irq = irq_of_parse_and_map(np, 0);
	if (pcs->socdata.irq)
		pcs->flags |= PCS_FEAT_IRQ;

	/* We still need auxdata for some omaps for PRM interrupts */
	pdata = dev_get_platdata(&pdev->dev);
	if (pdata) {
		if (pdata->rearm)
			pcs->socdata.rearm = pdata->rearm;
		if (pdata->irq) {
			pcs->socdata.irq = pdata->irq;
			pcs->flags |= PCS_FEAT_IRQ;
		}
	}
	//为0也不用管
	if (PCS_HAS_IRQ) {
		ret = pcs_irq_init_chained_handler(pcs, np);
		if (ret < 0)
			dev_warn(pcs->dev, "initialized with no interrupts\n");
	}

	dev_info(pcs->dev, "%i pins, size %u\n", pcs->desc.npins, pcs->size);

	return pinctrl_enable(pcs->pctl);

free:
	pcs_free_resources(pcs);

	return ret;
}

pcs_allocate_pin_table函数

static int pcs_allocate_pin_table(struct pcs_device *pcs)
{
	int mux_bytes, nr_pins, i;
	int num_pins_in_register = 0;
	//mux_bytes = 4
	mux_bytes = pcs->width / BITS_PER_BYTE;
	//pinctrl-single,bit-per-mux属性未定义
	//所以bits_per_mux =0
	if (pcs->bits_per_mux) {
		pcs->bits_per_pin = fls(pcs->fmask);
		nr_pins = (pcs->size * BITS_PER_BYTE) / pcs->bits_per_pin;
		num_pins_in_register = pcs->width / pcs->bits_per_pin;
	} else {
		nr_pins = pcs->size / mux_bytes;
	}
	//pmx_ctrl1节点:
	//nr_pins = 0x38/4 = 14
	//pmx_cfg1节点:
	//nr_pins = 0x5C/4 = 23

	dev_dbg(pcs->dev, "allocating %i pins\n", nr_pins);
	//这个pcs->dev就是device_node
	//分配nr_pins个struct pinctrl_pin_desc *pa;的内存大小给pcs->pins.pa
	pcs->pins.pa = devm_kcalloc(pcs->dev,
				nr_pins, sizeof(*pcs->pins.pa),
				GFP_KERNEL);
	if (!pcs->pins.pa)
		return -ENOMEM;
	//npins表示每个控制器pin的数目
	pcs->desc.pins = pcs->pins.pa;
	pcs->desc.npins = nr_pins;

	for (i = 0; i < pcs->desc.npins; i++) {
		unsigned offset;
		int res;
		int byte_num;
		int pin_pos = 0;
		//pcs->bits_per_mux为0执行的是下面的那一句
		if (pcs->bits_per_mux) {
			byte_num = (pcs->bits_per_pin * i) / BITS_PER_BYTE;
			offset = (byte_num / mux_bytes) * mux_bytes;
			pin_pos = i % num_pins_in_register;
		} else {
			//每次循环offset偏移加4
			offset = i * mux_bytes;
		}
		//传进来的pin_pos为0,这个函数貌似啥也没干,执行结束后只是pcs->pins.cur变成了14
		res = pcs_add_pin(pcs, offset, pin_pos);
		if (res < 0) {
			dev_err(pcs->dev, "error adding pins: %i\n", res);
			return res;
		}
	}

	printk("pcs_allocate_pin_table end\n");
	return 0;
}

pcs_add_pin函数

static int pcs_add_pin(struct pcs_device *pcs, unsigned offset,
		unsigned pin_pos)
{
	struct pcs_soc_data *pcs_soc = &pcs->socdata;
	struct pinctrl_pin_desc *pin;
	int i;
	i = pcs->pins.cur;
	if (i >= pcs->desc.npins) {
		dev_err(pcs->dev, "too many pins, max %i\n",
			pcs->desc.npins);
		return -ENOMEM;
	}


	if (pcs_soc->irq_enable_mask) {
		unsigned val;

		val = pcs->read(pcs->base + offset);

		if (val & pcs_soc->irq_enable_mask) {
			dev_dbg(pcs->dev, "irq enabled at boot for pin at %lx (%x), clearing\n",
				(unsigned long)pcs->res->start + offset, val);
			val &= ~pcs_soc->irq_enable_mask;
			pcs->write(val, pcs->base + offset);
		}
	}

	pin = &pcs->pins.pa[i];
	pin->number = i;
	pcs->pins.cur++;
	return i;
}

pinctrl_register_one_pin函数

static int pinctrl_register_one_pin(struct pinctrl_dev *pctldev,
				    const struct pinctrl_pin_desc *pin)
{
	struct pin_desc *pindesc;
	//查看是否已经注册这个pin
	pindesc = pin_desc_get(pctldev, pin->number);
	if (pindesc) {
		dev_err(pctldev->dev, "pin %d already registered\n",
			pin->number);
		return -EINVAL;
	}
	//分配内存
	pindesc = kzalloc(sizeof(*pindesc), GFP_KERNEL);
	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;
	//将该pin添加到pctldev中
	radix_tree_insert(&pctldev->pin_desc_tree, pin->number, pindesc);
	pr_debug("registered pin %d (%s) on %s\n",
		 pin->number, pindesc->name, pctldev->desc->name);
	return 0;
}

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);
	mutex_unlock(&pinctrldev_list_mutex);

	pinctrl_init_device_debugfs(pctldev);

	return 0;
}

pinctrl_claim_hogs函数

pinctrl_claim_hogs()
	//构建pinctrl结构体
	pctldev->p = create_pinctrl(pctldev->dev, pctldev);
	{
		//分配pin ctrl占用的内存并初始化;
		p = kzalloc(sizeof(*p), GFP_KERNEL); 
		//解析设备树节点信息
		ret = pinctrl_dt_to_map(p, pctldev);
		{
			for (state = 0; ; state++) {
				propname = kasprintf(GFP_KERNEL, "pinctrl-%d", state);
				//寻找这个节点下的pinctrl-%d属性
				prop = of_find_property(np, propname, &size);
				//根据state找到pinctrl-names中的第几个字符串,返回给statename
				ret = of_property_read_string_index(np, "pinctrl-names",
										    state, &statename);
				for (config = 0; config < size; config++) {
					phandle = be32_to_cpup(list++);
					//查找整个设备树。从根节点开始,找到属性带pinctrl-%d的device_node
					np_config = of_find_node_by_phandle(phandle);
					//这个函数会找到pinctrl-%d属性的父节点
					//调用父节点的pctldev->desc->pctlop->dt_node_to_map函数
					//本驱动中dt_node_to_map会根据pinctrl-single,pins属性来设置复用寄存器的值
					ret = dt_to_map_one_config(p, pctldev, statename,
											   np_config);
				}
			}
		}
	}
}

总结

主要结构体

pcs_device

 * struct pcs_device - pinctrl device instance
 * @res:	resources
 * @base:	virtual address of the controller
 * @saved_vals: saved values for the controller
 * @size:	size of the ioremapped area
 * @dev:	device entry
 * @np:		device tree node
 * @pctl:	pin controller device
 * @flags:	mask of PCS_FEAT_xxx values
 * @missing_nr_pinctrl_cells: for legacy binding, may go away
 * @socdata:	soc specific data
 * @lock:	spinlock for register access
 * @mutex:	mutex protecting the lists
 * @width:	bits per mux register
 * @fmask:	function register mask
 * @fshift:	function register shift
 * @foff:	value to turn mux off
 * @fmax:	max number of functions in fmask
 * @bits_per_mux: number of bits per mux
 * @bits_per_pin: number of bits per pin
 * @pins:	physical pins on the SoC
 * @gpiofuncs:	list of gpio functions
 * @irqs:	list of interrupt registers
 * @chip:	chip container for this instance
 * @domain:	IRQ domain for this instance
 * @desc:	pin controller descriptor
 * @read:	register read function to use
 * @write:	register write function to use
struct pcs_device {
	struct resource *res;
	void __iomem *base;
	void *saved_vals;
	unsigned size;
	struct device *dev;
	struct device_node *np;
	struct pinctrl_dev *pctl;
	unsigned flags;
#define PCS_CONTEXT_LOSS_OFF	(1 << 3)
#define PCS_QUIRK_SHARED_IRQ	(1 << 2)
#define PCS_FEAT_IRQ		(1 << 1)
#define PCS_FEAT_PINCONF	(1 << 0)
	struct property *missing_nr_pinctrl_cells;
	struct pcs_soc_data socdata;
	raw_spinlock_t lock;
	struct mutex mutex;
	unsigned width;
	unsigned fmask;
	unsigned fshift;
	unsigned foff;
	unsigned fmax;
	bool bits_per_mux;
	unsigned bits_per_pin;
	struct pcs_data pins;
	struct list_head gpiofuncs;
	struct list_head irqs;
	struct irq_chip chip;
	struct irq_domain *domain;
	struct pinctrl_desc desc;
	unsigned (*read)(void __iomem *reg);
	void (*write)(unsigned val, void __iomem *reg);
};

厂家自定义的结构体,probe函数主要是填充这个结构体,每个pinctrl控制器的节点会构造一个结构体

pinctrl_desc

/**
 * struct pinctrl_desc - pin controller descriptor, register this to pin
 * control subsystem
 * @name: name for the pin controller
 * @pins: an array of pin descriptors describing all the pins handled by
 *	this pin controller
 * @npins: number of descriptors in the array, usually just ARRAY_SIZE()
 *	of the pins field above
 * @pctlops: pin control operation vtable, to support global concepts like
 *	grouping of pins, this is optional.
 * @pmxops: pinmux operations vtable, if you support pinmuxing in your driver
 * @confops: pin config operations vtable, if you support pin configuration in
 *	your driver
 * @owner: module providing the pin controller, used for refcounting
 * @num_custom_params: Number of driver-specific custom parameters to be parsed
 *	from the hardware description
 * @custom_params: List of driver_specific custom parameters to be parsed from
 *	the hardware description
 * @custom_conf_items: Information how to print @params in debugfs, must be
 *	the same size as the @custom_params, i.e. @num_custom_params
 */
struct pinctrl_desc {
	const char *name;
	const struct pinctrl_pin_desc *pins;
	unsigned int npins;
	const struct pinctrl_ops *pctlops;
	const struct pinmux_ops *pmxops;
	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;
#endif
};

pinctrl_desc描述了该pinctrl设备的相关信息,引脚数量,引脚配置操作函数,硬件功能操作函数,引脚复用操作函数

struct pinctrl_ops {
  //获取系统中pin groups的个数,后续的操作,将以相应的索引为单位(类似数组的下标,个数为数组的大小)
 int (*get_groups_count) (struct pinctrl_dev *pctldev);
  //获取指定group(由索引selector指定)的名称
 const char *(*get_group_name) (struct pinctrl_dev *pctldev, unsigned selector);
  //获取指定group的所有pins(由索引selector指定),结果保存在pins(指针数组)和num_pins(指针)中
 int (*get_group_pins) (struct pinctrl_dev *pctldev, unsigned selector, const unsigned **pins, unsigned *num_pins);
 void (*pin_dbg_show) (struct pinctrl_dev *pctldev, struct seq_file *s, unsigned offset);
  //用于将device tree中的pin state信息转换为pin map
 int (*dt_node_to_map) (struct pinctrl_dev *pctldev, struct device_node *np_config, struct pinctrl_map **map, unsigned *num_maps);
 void (*dt_free_map) (struct pinctrl_dev *pctldev, struct pinctrl_map *map, unsigned num_maps);
};
struct pinmux_ops {
  //检查某个pin是否已作它用,用于管脚复用时的互斥
 int (*request) (struct pinctrl_dev *pctldev, unsigned offset);
  //request的反操作
 int (*free) (struct pinctrl_dev *pctldev, unsigned offset);
  //获取系统中function的个数
 int (*get_functions_count) (struct pinctrl_dev *pctldev);
  //获取指定function的名称
 const char *(*get_function_name) (struct pinctrl_dev *pctldev, unsigned selector);
  //获取指定function所占用的pin group
 int (*get_function_groups) (struct pinctrl_dev *pctldev, unsigned selector, const char * const **groups, unsigned *num_groups);
  //将指定的pin group(group_selector)设置为指定的function(func_selector)
 int (*set_mux) (struct pinctrl_dev *pctldev, unsigned func_selector, unsigned group_selector);
  //以下是gpio相关的操作
 int (*gpio_request_enable) (struct pinctrl_dev *pctldev, struct pinctrl_gpio_range *range, unsigned offset);
 void (*gpio_disable_free) (struct pinctrl_dev *pctldev, struct pinctrl_gpio_range *range, unsigned offset);
 int (*gpio_set_direction) (struct pinctrl_dev *pctldev, struct pinctrl_gpio_range *range, unsigned offset, bool input);
  //为true时,说明该pin controller不允许某个pin作为gpio和其它功能同时使用
 bool strict;
};
struct pinconf_ops {
#ifdef CONFIG_GENERIC_PINCONF
 bool is_generic;
#endif
  //获取指定 pin 的当前配置,保存在 config 指针中
 int (*pin_config_get) (struct pinctrl_dev *pctldev, unsigned pin, unsigned long *config);
  //设置指定pin的配置
 int (*pin_config_set) (struct pinctrl_dev *pctldev, unsigned pin, unsigned long *configs, unsigned num_configs);
  //获取指定pin group的配置项
 int (*pin_config_group_get) (struct pinctrl_dev *pctldev, unsigned selector, unsigned long *config);
  //设置指定pin group的配置项
 int (*pin_config_group_set) (struct pinctrl_dev *pctldev, unsigned selector, unsigned long *configs, unsigned num_configs);
  ......

pinctrl_dev

/**
 * struct pinctrl_dev - pin control class device
 * @node: node to include this pin controller in the global pin controller list
 * @desc: the pin controller descriptor supplied when initializing this pin
 *	controller
 * @pin_desc_tree: each pin descriptor for this pin controller is stored in
 *	this radix tree
 * @pin_group_tree: optionally each pin group can be stored in this radix tree
 * @num_groups: optionally number of groups can be kept here
 * @pin_function_tree: optionally each function can be stored in this radix tree
 * @num_functions: optionally number of functions can be kept here
 * @gpio_ranges: a list of GPIO ranges that is handled by this pin controller,
 *	ranges are added to this list at runtime
 * @dev: the device entry for this pin controller
 * @owner: module providing the pin controller, used for refcounting
 * @driver_data: driver data for drivers registering to the pin controller
 *	subsystem
 * @p: result of pinctrl_get() for this device
 * @hog_default: default state for pins hogged by this device
 * @hog_sleep: sleep state for pins hogged by this device
 * @mutex: mutex taken on each pin controller specific action
 * @device_root: debugfs root for this device
 */
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
};

总结

  probe函数填充pcs_device结构体信息,pcs_allocate_pin_table遍历出所有pin的树木和信息,设置pcs->desc.pins和pcs->desc.npins。指向pinctrl_register_and_init,主要是为了构造pinctrl_dev结构体,初始化了pin_desc_tree、pin_group_tree、pin_function_tree三个树,检查pctldev->desc->pctlops、pmxops、pmxops是否有必要的函数,让后将每个pin的pin_desc加入到pinctrl_dev的pin_desc_tree串起来。pcs_add_gpio_func去device_node找pinctrl-single,gpio-range和#pinctrl-single,gpio-range-cells,没有就直接返回了。pinctrl_enable还会解析设备树节点查找是否有设置过pinctrl-%d和pinctrl-names的信息,pinctrl-%d属性的值是要使用pinctrl的节点,调用dt_node_to_map会根据pinctrl-single,pins属性来设置复用寄存器的值。gpio的子系统底层也会调用pinctrl,以后在研究

你可能感兴趣的:(linux,单片机,嵌入式硬件)