【Linux 驱动】IMX6ULL pinctrl驱动

news2024/9/25 15:21:42

1. 概述

  • Linux 驱动讲究驱动分离与分层,pinctrl 和 gpio 子系统就是驱动分离与分层思想下的产物。
  • pinctrl顾名思义就是引脚控制,用来配置比如引脚mux复用信息,引脚电器属性(比如上/下拉、速度、驱动能力等)信息。
  • gpio顾名思义就是控制gpio的输入输出,以及高低电平。不过,大多数的芯片并没有单独的IOMUX模块,引脚的复用、配置等,而是在GPIO模块内部实现的。

2. pin controller的数据结构

2.1 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
 * @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;    //提供具体操作方法和抽象包括pincrtl_ops函数,pinmux操作函数和pin的描述等
	struct radix_tree_root pin_desc_tree;
	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
};

2.2 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;
	struct pinctrl_pin_desc const *pins;        //描述一个pin控制器的引脚
	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
};

2.3 pinctrl_pin_desc

/**
 * struct pinctrl_pin_desc - boards/machines provide information on their
 * pins, pads or other muxable units in this struct
 * @number: unique pin number from the global pin number space
 * @name: a name for this pin
 * @drv_data: driver-defined per-pin data. pinctrl core does not touch this
 */
struct pinctrl_pin_desc {
	unsigned number;     //引脚序号
	const char *name;    //引脚名称
	void *drv_data;
};

2.4 pinctrl_ops

/**
 * struct pinctrl_ops - global pin control operations, to be implemented by
 * pin controller drivers.
 * @get_groups_count: Returns the count of total number of groups registered.
 * @get_group_name: return the group name of the pin group
 * @get_group_pins: return an array of pins corresponding to a certain
 *	group selector @pins, and the size of the array in @num_pins
 * @pin_dbg_show: optional debugfs display hook that will provide per-device
 *	info for a certain pin in debugfs
 * @dt_node_to_map: parse a device tree "pin configuration node", and create
 *	mapping table entries for it. These are returned through the @map and
 *	@num_maps output parameters. This function is optional, and may be
 *	omitted for pinctrl drivers that do not support device tree.
 * @dt_free_map: free mapping table entries created via @dt_node_to_map. The
 *	top-level @map pointer must be freed, along with any dynamically
 *	allocated members of the mapping table entries themselves. This
 *	function is optional, and may be omitted for pinctrl drivers that do
 *	not support device tree.
 */
struct pinctrl_ops {
	int (*get_groups_count) (struct pinctrl_dev *pctldev);    //获取组数
	const char *(*get_group_name) (struct pinctrl_dev *pctldev,    //获取组名
				       unsigned selector);
	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,    //用以debugfs提供每个引脚的信息
			  unsigned offset);
	int (*dt_node_to_map) (struct pinctrl_dev *pctldev,        //解析设备树节点,转换成pinctrl_map,重点
			       struct device_node *np_config,
			       struct pinctrl_map **map, unsigned *num_maps);
	void (*dt_free_map) (struct pinctrl_dev *pctldev,        //释放map
			     struct pinctrl_map *map, unsigned num_maps);
};

2.5 pinmux_ops

/**
 * struct pinmux_ops - pinmux operations, to be implemented by pin controller
 * drivers that support pinmuxing
 * @request: called by the core to see if a certain pin can be made
 *	available for muxing. This is called by the core to acquire the pins
 *	before selecting any actual mux setting across a function. The driver
 *	is allowed to answer "no" by returning a negative error code
 * @free: the reverse function of the request() callback, frees a pin after
 *	being requested
 * @get_functions_count: returns number of selectable named functions available
 *	in this pinmux driver
 * @get_function_name: return the function name of the muxing selector,
 *	called by the core to figure out which mux setting it shall map a
 *	certain device to
 * @get_function_groups: return an array of groups names (in turn
 *	referencing pins) connected to a certain function selector. The group
 *	name can be used with the generic @pinctrl_ops to retrieve the
 *	actual pins affected. The applicable groups will be returned in
 *	@groups and the number of groups in @num_groups
 * @set_mux: enable a certain muxing function with a certain pin group. The
 *	driver does not need to figure out whether enabling this function
 *	conflicts some other use of the pins in that group, such collisions
 *	are handled by the pinmux subsystem. The @func_selector selects a
 *	certain function whereas @group_selector selects a certain set of pins
 *	to be used. On simple controllers the latter argument may be ignored
 * @gpio_request_enable: requests and enables GPIO on a certain pin.
 *	Implement this only if you can mux every pin individually as GPIO. The
 *	affected GPIO range is passed along with an offset(pin number) into that
 *	specific GPIO range - function selectors and pin groups are orthogonal
 *	to this, the core will however make sure the pins do not collide.
 * @gpio_disable_free: free up GPIO muxing on a certain pin, the reverse of
 *	@gpio_request_enable
 * @gpio_set_direction: Since controllers may need different configurations
 *	depending on whether the GPIO is configured as input or output,
 *	a direction selector function may be implemented as a backing
 *	to the GPIO controllers that need pin muxing.
 */
struct pinmux_ops {
    /*检查某个pin是否已作它用,用于管脚复用时的互斥(避免多个功能同时使用某个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 * const 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);
};

2.6 pinconf_ops

/**
 * struct pinconf_ops - pin config operations, to be implemented by
 * pin configuration capable drivers.
 * @is_generic: for pin controllers that want to use the generic interface,
 *	this flag tells the framework that it's generic.
 * @pin_config_get: get the config of a certain pin, if the requested config
 *	is not available on this controller this should return -ENOTSUPP
 *	and if it is available but disabled it should return -EINVAL
 * @pin_config_set: configure an individual pin
 * @pin_config_group_get: get configurations for an entire pin group
 * @pin_config_group_set: configure all pins in a group
 * @pin_config_dbg_parse_modify: optional debugfs to modify a pin configuration
 * @pin_config_dbg_show: optional debugfs display hook that will provide
 *	per-device info for a certain pin in debugfs
 * @pin_config_group_dbg_show: optional debugfs display hook that will provide
 *	per-device info for a certain group in debugfs
 * @pin_config_config_dbg_show: optional debugfs display hook that will decode
 *	and display a driver's pin configuration parameter
 */
struct pinconf_ops {
#ifdef CONFIG_GENERIC_PINCONF
	bool is_generic;
#endif
	int (*pin_config_get) (struct pinctrl_dev *pctldev,    //获取单个引脚配置
			       unsigned pin,
			       unsigned long *config);
	int (*pin_config_set) (struct pinctrl_dev *pctldev,    //配置单个引脚
			       unsigned pin,
			       unsigned long *configs,
			       unsigned num_configs);
	int (*pin_config_group_get) (struct pinctrl_dev *pctldev,    //获取某组引脚配置
				     unsigned selector,
				     unsigned long *config);
	int (*pin_config_group_set) (struct pinctrl_dev *pctldev,    //配置某组引脚
				     unsigned selector,
				     unsigned long *configs,
				     unsigned num_configs);
	int (*pin_config_dbg_parse_modify) (struct pinctrl_dev *pctldev,    //用以debugfs修改pin配置信息
					   const char *arg,
					   unsigned long *config);
	void (*pin_config_dbg_show) (struct pinctrl_dev *pctldev,    //用以debugfs提供pin配置信息
				     struct seq_file *s,
				     unsigned offset);
	void (*pin_config_group_dbg_show) (struct pinctrl_dev *pctldev,    //用以debugfs提供group配置信息
					   struct seq_file *s,
					   unsigned selector);
	void (*pin_config_config_dbg_show) (struct pinctrl_dev *pctldev,    //用以debugfs解析并显示pin的配置
					    struct seq_file *s,
					    unsigned long config);
};

2.7 pinctrl_map

/**
 * struct pinctrl_map - boards/machines shall provide this map for devices
 * @dev_name: the name of the device using this specific mapping, the name
 *	must be the same as in your struct device*. If this name is set to the
 *	same name as the pin controllers own dev_name(), the map entry will be
 *	hogged by the driver itself upon registration
 * @name: the name of this specific map entry for the particular machine.
 *	This is the parameter passed to pinmux_lookup_state()
 * @type: the type of mapping table entry
 * @ctrl_dev_name: the name of the device controlling this specific mapping,
 *	the name must be the same as in your struct device*. This field is not
 *	used for PIN_MAP_TYPE_DUMMY_STATE
 * @data: Data specific to the mapping type
 */
struct pinctrl_map {
	const char *dev_name;    //设备名称
	const char *name;        //该pinctrl_map对应的状态(default、idle、sleep等
	enum pinctrl_map_type type;    //pinctrl_map的类型,包括mux group、config group、config pins等
	const char *ctrl_dev_name;    //pinctrl device的名称,根据该名称可获取到soc pin controller对应的pinctrl device
	union {
		struct pinctrl_map_mux mux;    //引脚复用的内容,该数据结构中包含function名称、group名称,通过function、group就可以确定进行引脚复用的引脚id与引脚复用值等信息
		struct pinctrl_map_configs configs;    //引脚配置相关的内容,包括group或者pin的名称,以及该group、pin的配置信息,实现引脚配置操作。
	} data;
};

3 client的数据结构

3.1  dev_pin_info

/**
 * struct dev_pin_info - pin state container for devices
 * @p: pinctrl handle for the containing device
 * @default_state: the default state for the handle, if found
 */
struct dev_pin_info {
	struct pinctrl *p;
	struct pinctrl_state *default_state;
#ifdef CONFIG_PM
	struct pinctrl_state *sleep_state;
	struct pinctrl_state *idle_state;
#endif
};

3.2 pinctrl_state

/**
 * struct pinctrl_state - a pinctrl state for a device
 * @node: list node for struct pinctrl's @states field
 * @name: the name of this state
 * @settings: a list of settings for this state
 */
struct pinctrl_state {
	struct list_head node;
	const char *name;
	struct list_head settings;
};

4. pincontroller构造过程

4.1. platform匹配过程

4.2. probe过程 

解析后大致数据指向如下图:

4.3. struct pinctrl_ops

4.3.1. get_groups_count(获取组数)

static int imx_get_groups_count(struct pinctrl_dev *pctldev)
{
	struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
	const struct imx_pinctrl_soc_info *info = ipctl->info;

	return info->ngroups;
}

4.3.2 get_group_name(获取组的名字)

static const char *imx_get_group_name(struct pinctrl_dev *pctldev,
				       unsigned selector)
{
	struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
	const struct imx_pinctrl_soc_info *info = ipctl->info;

	return info->groups[selector].name;
}

 4.3.3 get_group_pins(获取组的引脚)

static int imx_get_group_pins(struct pinctrl_dev *pctldev, unsigned selector,
			       const unsigned **pins,
			       unsigned *npins)
{
	struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
	const struct imx_pinctrl_soc_info *info = ipctl->info;

	if (selector >= info->ngroups)
		return -EINVAL;

	*pins = info->groups[selector].pin_ids;
	*npins = info->groups[selector].npins;

	return 0;
}

4.3.4 dt_node_to_map (将设备树节点转为map结构体)

static int imx_dt_node_to_map(struct pinctrl_dev *pctldev,
			struct device_node *np,
			struct pinctrl_map **map, unsigned *num_maps)
{
	struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
	const struct imx_pinctrl_soc_info *info = ipctl->info;
	const struct imx_pin_group *grp;
	struct pinctrl_map *new_map;
	struct device_node *parent;
	int map_num = 1;
	int i, j;

	/*
	 * first find the group of this node and check if we need create
	 * config maps for pins
	 */
    /* 通过节点名称找到组 */
	grp = imx_pinctrl_find_group_by_name(info, np->name);
	if (!grp) {
		dev_err(info->dev, "unable to find group for node %s\n",
			np->name);
		return -EINVAL;
	}

    /* 是否需要配置 */
	for (i = 0; i < grp->npins; i++) {
		if (!(grp->pins[i].config & IMX_NO_PAD_CTL))
			map_num++;
	}

    /* 申请map内存 */
	new_map = kmalloc(sizeof(struct pinctrl_map) * map_num, GFP_KERNEL);
	if (!new_map)
		return -ENOMEM;

	*map = new_map;
	*num_maps = map_num;

	/* create mux map */
	parent = of_get_parent(np);
	if (!parent) {
		kfree(new_map);
		return -EINVAL;
	}

    /* 第0个设置为复用 */
	new_map[0].type = PIN_MAP_TYPE_MUX_GROUP;
	new_map[0].data.mux.function = parent->name;
	new_map[0].data.mux.group = np->name;
	of_node_put(parent);


	/* create config map */
    /* 配置map */
	new_map++;
	for (i = j = 0; i < grp->npins; i++) {
		if (!(grp->pins[i].config & IMX_NO_PAD_CTL)) {
			new_map[j].type = PIN_MAP_TYPE_CONFIGS_PIN;
			new_map[j].data.configs.group_or_pin =
					pin_get_name(pctldev, grp->pins[i].pin);
			new_map[j].data.configs.configs = &grp->pins[i].config;
			new_map[j].data.configs.num_configs = 1;
			j++;
		}
	}

	dev_dbg(pctldev->dev, "maps: function %s group %s num %d\n",
		(*map)->data.mux.function, (*map)->data.mux.group, map_num);

	return 0;
}

以上述ft5x06_pins为例:

 4.3.5 dt_free_map

static void imx_dt_free_map(struct pinctrl_dev *pctldev,
				struct pinctrl_map *map, unsigned num_maps)
{
	kfree(map);
}

4.4 struct pinmux_ops

4.4.1 imx_pmx_get_funcs_count(获取功能的个数)

static int imx_pmx_get_funcs_count(struct pinctrl_dev *pctldev)
{
	struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
	const struct imx_pinctrl_soc_info *info = ipctl->info;

	return info->nfunctions;
}

4.4.2 get_function_name(获取功能的名字)

static const char *imx_pmx_get_func_name(struct pinctrl_dev *pctldev,
					  unsigned selector)
{
	struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
	const struct imx_pinctrl_soc_info *info = ipctl->info;

	return info->functions[selector].name;
}

4.4.3 imx_pmx_get_groups (获取组)

static int imx_pmx_get_groups(struct pinctrl_dev *pctldev, unsigned selector,
			       const char * const **groups,
			       unsigned * const num_groups)
{
	struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
	const struct imx_pinctrl_soc_info *info = ipctl->info;

	*groups = info->functions[selector].groups;
	*num_groups = info->functions[selector].num_groups;

	return 0;
}

4.4.4 set_mux (设置复用)

static int imx_pmx_set(struct pinctrl_dev *pctldev, unsigned selector,
		       unsigned group)
{
	struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
	const struct imx_pinctrl_soc_info *info = ipctl->info;
	const struct imx_pin_reg *pin_reg;
	unsigned int npins, pin_id;
	int i;
	struct imx_pin_group *grp;

	/*
	 * Configure the mux mode for each pin in the group for a specific
	 * function.
	 */
	grp = &info->groups[group];
	npins = grp->npins;

	dev_dbg(ipctl->dev, "enable function %s group %s\n",
		info->functions[selector].name, grp->name);

	for (i = 0; i < npins; i++) {
		struct imx_pin *pin = &grp->pins[i];
		pin_id = pin->pin;
		pin_reg = &info->pin_regs[pin_id];

		if (pin_reg->mux_reg == -1) {
			dev_err(ipctl->dev, "Pin(%s) does not support mux function\n",
				info->pins[pin_id].name);
			return -EINVAL;
		}

		if (info->flags & SHARE_MUX_CONF_REG) {
			u32 reg;
			reg = readl(ipctl->base + pin_reg->mux_reg);
			reg &= ~(0x7 << 20);
			reg |= (pin->mux_mode << 20);
			writel(reg, ipctl->base + pin_reg->mux_reg);
		} else {
			writel(pin->mux_mode, ipctl->base + pin_reg->mux_reg);
		}
		dev_dbg(ipctl->dev, "write: offset 0x%x val 0x%x\n",
			pin_reg->mux_reg, pin->mux_mode);

		/*
		 * If the select input value begins with 0xff, it's a quirky
		 * select input and the value should be interpreted as below.
		 *     31     23      15      7        0
		 *     | 0xff | shift | width | select |
		 * It's used to work around the problem that the select
		 * input for some pin is not implemented in the select
		 * input register but in some general purpose register.
		 * We encode the select input value, width and shift of
		 * the bit field into input_val cell of pin function ID
		 * in device tree, and then decode them here for setting
		 * up the select input bits in general purpose register.
		 */
		if (pin->input_val >> 24 == 0xff) {
			u32 val = pin->input_val;
			u8 select = val & 0xff;
			u8 width = (val >> 8) & 0xff;
			u8 shift = (val >> 16) & 0xff;
			u32 mask = ((1 << width) - 1) << shift;
			/*
			 * The input_reg[i] here is actually some IOMUXC general
			 * purpose register, not regular select input register.
			 */
			val = readl(ipctl->base + pin->input_reg);
			val &= ~mask;
			val |= select << shift;
			writel(val, ipctl->base + pin->input_reg);
		} else if (pin->input_reg) {
			/*
			 * Regular select input register can never be at offset
			 * 0, and we only print register value for regular case.
			 */
			if (ipctl->input_sel_base)
				writel(pin->input_val, ipctl->input_sel_base +
						pin->input_reg);
			else
				writel(pin->input_val, ipctl->base +
						pin->input_reg);
			dev_dbg(ipctl->dev,
				"==>select_input: offset 0x%x val 0x%x\n",
				pin->input_reg, pin->input_val);
		}
	}

	return 0;
}

4.4.5 gpio_request_enable (引脚使能)

static int imx_pmx_gpio_request_enable(struct pinctrl_dev *pctldev,
			struct pinctrl_gpio_range *range, unsigned offset)
{
	struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
	const struct imx_pinctrl_soc_info *info = ipctl->info;
	const struct imx_pin_reg *pin_reg;
	struct imx_pin_group *grp;
	struct imx_pin *imx_pin;
	unsigned int pin, group;
	u32 reg;

	/* Currently implementation only for shared mux/conf register */
	if (!(info->flags & SHARE_MUX_CONF_REG))
		return -EINVAL;

	pin_reg = &info->pin_regs[offset];
	if (pin_reg->mux_reg == -1)
		return -EINVAL;

	/* Find the pinctrl config with GPIO mux mode for the requested pin */
	for (group = 0; group < info->ngroups; group++) {
		grp = &info->groups[group];
		for (pin = 0; pin < grp->npins; pin++) {
			imx_pin = &grp->pins[pin];
			if (imx_pin->pin == offset && !imx_pin->mux_mode)
				goto mux_pin;
		}
	}

	return -EINVAL;

mux_pin:
	reg = readl(ipctl->base + pin_reg->mux_reg);
	reg &= ~(0x7 << 20);
	reg |= imx_pin->config;
	writel(reg, ipctl->base + pin_reg->mux_reg);

	return 0;
}

4.4.6 gpio_set_direction(设置引脚方向)

static int imx_pmx_gpio_set_direction(struct pinctrl_dev *pctldev,
	   struct pinctrl_gpio_range *range, unsigned offset, bool input)
{
	struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
	const struct imx_pinctrl_soc_info *info = ipctl->info;
	const struct imx_pin_reg *pin_reg;
	u32 reg;

	/*
	 * Only Vybrid has the input/output buffer enable flags (IBE/OBE)
	 * They are part of the shared mux/conf register.
	 */
	if (!(info->flags & SHARE_MUX_CONF_REG))
		return -EINVAL;

	pin_reg = &info->pin_regs[offset];
	if (pin_reg->mux_reg == -1)
		return -EINVAL;

	/* IBE always enabled allows us to read the value "on the wire" */
	reg = readl(ipctl->base + pin_reg->mux_reg);
	if (input)
		reg &= ~0x2;
	else
		reg |= 0x2;
	writel(reg, ipctl->base + pin_reg->mux_reg);

	return 0;
}

4.5 struct pinconf_ops

4.5.1 pin_config_get(获取配置)

static int imx_pinconf_get(struct pinctrl_dev *pctldev,
			     unsigned pin_id, unsigned long *config)
{
	struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
	const struct imx_pinctrl_soc_info *info = ipctl->info;
	const struct imx_pin_reg *pin_reg = &info->pin_regs[pin_id];

	if (pin_reg->conf_reg == -1) {
		dev_err(info->dev, "Pin(%s) does not support config function\n",
			info->pins[pin_id].name);
		return -EINVAL;
	}

	*config = readl(ipctl->base + pin_reg->conf_reg);

	if (info->flags & SHARE_MUX_CONF_REG)
		*config &= 0xffff;

	return 0;
}

4.5.2 pin_config_set(配置引脚)

static int imx_pinconf_set(struct pinctrl_dev *pctldev,
			     unsigned pin_id, unsigned long *configs,
			     unsigned num_configs)
{
	struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
	const struct imx_pinctrl_soc_info *info = ipctl->info;
	const struct imx_pin_reg *pin_reg = &info->pin_regs[pin_id];
	int i;

	if (pin_reg->conf_reg == -1) {
		dev_err(info->dev, "Pin(%s) does not support config function\n",
			info->pins[pin_id].name);
		return -EINVAL;
	}

	dev_dbg(ipctl->dev, "pinconf set pin %s\n",
		info->pins[pin_id].name);

	for (i = 0; i < num_configs; i++) {
		if (info->flags & SHARE_MUX_CONF_REG) {
			u32 reg;
			reg = readl(ipctl->base + pin_reg->conf_reg);
			reg &= ~0xffff;
			reg |= configs[i];
			writel(reg, ipctl->base + pin_reg->conf_reg);
		} else {
			writel(configs[i], ipctl->base + pin_reg->conf_reg);
		}
		dev_dbg(ipctl->dev, "write: offset 0x%x val 0x%lx\n",
			pin_reg->conf_reg, configs[i]);
	} /* for each config */

	return 0;
}

5. client节点的pinctrl构造过程

函数调用

really_probe
    pinctrl_bind_pins
        dev->pins = devm_kzalloc(dev, sizeof(*(dev->pins)), GFP_KERNEL);
        
        dev->pins->p = devm_pinctrl_get(dev);
                            pinctrl_get
                                create_pinctrl(dev);
                                    ret = pinctrl_dt_to_map(p);
                                    
                                    for_each_maps(maps_node, i, map) {
                                        ret = add_setting(p, map);
                                    }
        
        dev->pins->default_state = pinctrl_lookup_state(dev->pins->p,
                    PINCTRL_STATE_DEFAULT);        

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2053193.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

学会区分大模型——大模型的分类,让你更清晰的认识大模型

乱花渐欲迷人眼&#xff0c;学会从根本上认识问题 现在市面上大模型如百花齐放&#xff0c;对很多人来说一堆大模型带来的不是简单方便&#xff0c;而是乱七八糟以及迷茫。 因为不知道不同的大模型之间有什么区别&#xff0c;也不知道自己需要什么样的大模型&#xff1b;就拿…

【C++题解】1375. 拦截导弹方案求解

问题&#xff1a;1375. 拦截导弹方案求解 类型&#xff1a;贪心 题目描述&#xff1a; 某国为了防御敌国的导弹袭击&#xff0c;发展出一种导弹拦截系统。但是这种导弹拦截系统有一个缺陷&#xff1a; 虽然它的第一发炮弹能够到达任意的高度&#xff0c;但是以后每一发炮弹都…

理解Flink数据流图

前言 在大数据处理的世界里&#xff0c;Apache Flink 已经成为处理实时数据流的一个强大工具。Flink 提供了一种高度灵活的方法来构建复杂的数据处理管道&#xff0c;其核心是所谓的 DataFlow 图模型。本文将带你深入了解 Flink DataFlow 图的基础知识&#xff0c;帮助你理解它…

Hadoop入门基础(一):深入探索Hadoop内部处理流程与核心三剑客

在大数据的世界里&#xff0c;处理海量数据的需求越来越多&#xff0c;而Hadoop作为开源的分布式计算框架&#xff0c;成为了这一领域的核心技术之一。 一、Hadoop简介 Hadoop是Apache Software Foundation开发的一个开源分布式计算框架&#xff0c;旨在使用简单的编程模型来…

别再问了!微信小程序的那些事儿,一文搞定

微信小程序是一种无需下载安装即可使用的应用&#xff0c;它嵌入在微信生态中&#xff0c;用户通过微信扫一扫或搜索即可快速访问。 无论是购物、订餐、预约服务&#xff0c;还是玩个小游戏、看篇文章&#xff0c;都不需要下载额外的APP&#xff0c;直接就能在微信里搞定。不会…

Leading SAFe领导大规模敏捷认证公开课

课程简介 SAFe – Scaled Agile Framework是目前全球最广泛使用的大规模敏捷框架&#xff0c;也是全球敏捷相关认证中增长最快、最受认可的规模化敏捷认证。全球已有超过120万名SAFe认证专业人士。据官方统计&#xff0c;获得SAFe认证的IT专业人士平均工资增长13,000美元&…

C++:模拟实现string

前言&#xff1a; 为了更好的理解string底层的原理&#xff0c;我们将模拟实现string类中常用的函数接口。为了与std里的string进行区分&#xff0c;所以用命名空间来封装一个自己的strin类。 string.h #pragma once #define _CRT_SECURE_NO_WARNINGS 1#include<iostream&…

arm 的寄存器概述(8)

关于寄存器的概述。 带 三角形的是 这种模式下 独有的寄存器&#xff0c;也就是说&#xff0c;FIQ模式下与 SYstem/user 模式下&#xff0c;虽然都有r8 寄存器&#xff0c;但是不是一个东西。 r13 (SP ) 这是堆栈指针&#xff0c; r15(PC ) 这是 code 的指针。 r14(LR ), 这…

自动化与高效设计:推理技术在FPGA中的应用

想象一下&#xff0c;你正在设计一个复杂的电路系统&#xff0c;就像在搭建一座精巧的积木城堡。你手头有各种形状和功能的积木块&#xff0c;这些积木块可以组合成任何你需要的结构。在这个过程中&#xff0c;你有两种主要的方法&#xff1a;一种是手动挑选和搭建每一块积木&a…

安装JDK与配置环境变量

安装JDK与配置环境变量 JDK安装包所在路径&#xff1a;/opt/software/jdk-8u221-linux-x64.tar.gz 详细步骤 安装JDK与配置环境变量一、进入JDK安装目录/opt/software二、解压“jdk-8u221-linux-x64.tar.gz”安装包至当前目录三、查看/opt/software/目录下解压文件四、编辑系统…

鹅厂探索国漫新方向,谁家新作能不负期待?

上周一年一度的腾讯视频动漫大赏年度发布会结束了&#xff0c;但动漫迷们的讨论却没有停止。此次的片单分为“气”“大怪”“阁”三大主题&#xff0c;今天来和大家回顾解读一下“气”和“阁”有哪些看点吧。 首先想谈一谈“阁”&#xff0c;它是平台在内容升级思路上的体现&am…

C指针汇总——藏在数组名与指针之间的异同及使用细节

指针与数组的异同 数组名&#xff1a; 是一个指针常量(数组名的值是数组首元素的指针常量)&#xff0c;指向数组的首元素。大小固定为整个数组的大小。无法被改变或重新赋值(这里指数组名不能被赋值(指针常量不能指向其它地址)&#xff0c;数组元素是可以被重新设置的)。无法进…

企业CAD图纸加密软件推荐!2024年好用的10款CAD图纸加密软件排行

在现代企业中&#xff0c;CAD图纸作为重要的设计和工程数据&#xff0c;其安全性和保密性至关重要。为了防止图纸被非法获取、篡改或滥用&#xff0c;选择一款高效的CAD图纸加密软件显得尤为重要。本文将为您推荐2024年市场上十款好用的CAD图纸加密软件&#xff0c;帮助企业保护…

2024最新50道NLP和人工智能领域面试题+答案(中文+英文双版本)

编者按&#xff1a;分享一个很硬核的免费人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c; 可以当故事来看&#xff0c;轻松学习。 中文版本 自然语言处理 (NLP)已成为语言学、人工智能和计算机科学交叉领域的变革性领域。随着文本数据量的不断增加&…

图形编辑器基于Paper.js教程15:在Paper.js中实现拖拽图片导入画布功能

在现代Web开发中&#xff0c;用户体验是至关重要的。而拖拽文件上传的功能&#xff0c;不仅直观易用&#xff0c;还提升了用户与界面的交互体验。在这篇文章中&#xff0c;我们将探讨如何使用Paper.js和HTML5的拖放API&#xff0c;来实现将图片文件直接拖拽并导入到Paper.js的画…

如何让图片清晰度变高?介绍三种转变方案

如何让图片清晰度变高&#xff1f;在数字化时代&#xff0c;图片的质量直接影响着信息传递的效果。但由于拍摄条件、传输方式或存储时间的限制&#xff0c;我们时常会遇到图片清晰度不足的问题。还好随着技术的进步&#xff0c;现在有多种方法可以有效提升图片的清晰度。下文将…

arm 的模式+异常(7)

1 Byte , 8 bit, HarlfWord , 16bit , word ,32bit. 2 在内存中每一字节都有一个地址与它对应。 3 操作系统的8种模式 用户模式&#xff1a; 不能访问硬件资源&#xff0c;但是可以通过系统调用来访问。 疑问&#xff1a; 那不还是可以访问硬件资源吗&#xff1f; 系统模…

Zookeeper集群如何实现强一致性和高可用,集群数据同步过程

在分布式系统中&#xff0c;通常会面临如下问题&#xff1a; 分布式协调&#xff1a;在分布式环境下&#xff0c;多个节点需要协同工作&#xff0c;确保多个服务之间数据的一致性以及系统的可靠性。 分布式锁&#xff1a;在分布式系统中&#xff0c;多个节点可能需要同时访问共…

ppt模板软件哪个好?这5个工具提供各种类型的PPT模板

在筹备一场关于中元节的精彩演讲时&#xff0c;你是否曾陷入过寻找完美PPT模板的困境&#xff1f;那些千篇一律的设计是否让你觉得乏味&#xff0c;渴望一份创意与美感并存的视觉呈现&#xff1f; 别担心&#xff0c;今天&#xff0c;我将为你揭晓几款宝藏级软件&#xff0c;它…

如何为 Nextcloud 配置自动数据库备份 - 应用程序

自动数据库备份模块简化了生成数据库计划备份的过程。这些备份可以存储在各种位置&#xff0c;包括本地驱动器、FTP 服务器、SFTP 服务器、Dropbox、Google Drive、OneDrive、NextCloud 和 Amazon S3 云存储。用户还可以选择启用自动删除过期备份的功能。此外&#xff0c;用户可…