staticintrockchip_pinctrl_parse_groups(struct device_node *np, struct rockchip_pin_group *grp, struct rockchip_pinctrl *info, u32 index) { structdevice *dev = info->dev; structrockchip_pin_bank *bank; int size; const __be32 *list; int num; int i, j; int ret; // 打印调试信息,显示正在解析的组节点和索引 dev_dbg(dev, "group(%d): %pOFn\n", index, np);
/* Initialise group */ // 初始化组信,将引脚组的名称设置为节点的名称 grp->name = np->name;
/* * the binding format is rockchip,pins = <bank pin mux CONFIG>, * do sanity check and calculate pins number */ /* * 绑定格式为 rockchip,pins = <bank pin mux CONFIG>, * 进行合法性检查并计算引脚数量 */ list = of_get_property(np, "rockchip,pins", &size); /* we do not check return since it's safe node passed down */ size /= sizeof(*list); if (!size || size % 4)//如果属性值为空或者数量不是 4 的倍数 return dev_err_probe(dev, -EINVAL, "wrong pins number or pins and configs should be by 4\n");
grp->npins = size / 4;// 计算组的引脚数量 // 根据计算得到的引脚数量为引脚数组和数据数组分配内存空间,这些数组将用于存储引脚的编号和相关的配置信息 grp->pins = devm_kcalloc(dev, grp->npins, sizeof(*grp->pins), GFP_KERNEL); grp->data = devm_kcalloc(dev, grp->npins, sizeof(*grp->data), GFP_KERNEL); if (!grp->pins || !grp->data) return -ENOMEM; // 遍历列表中的每个元素,每 4 个元素表示一个引脚的信息 for (i = 0, j = 0; i < size; i += 4, j++) { const __be32 *phandle; structdevice_node *np_config; // 获取管脚号 num = be32_to_cpu(*list++); // 引脚号转换为对应的引脚结构体指针 bank = bank_num_to_bank(info, num); if (IS_ERR(bank)) return PTR_ERR(bank); // 根据引脚结构体中的引脚基地址(pin_base)和列表中的值计算引脚的编号,并将其存储在引脚数组(grp->pins)中 grp->pins[j] = bank->pin_base + be32_to_cpu(*list++); // 从列表中获取与当前引脚相关的功能选择值,并将其存储在数据数组(grp->data)中的相应位置 grp->data[j].func = be32_to_cpu(*list++);
// 获取与引脚相关的配置信息 phandle = list++; if (!phandle) return -EINVAL; // 从列表中获取与当前引脚相关的配置信息的句柄,并通过该句柄查找对应的配置节点(np_config) np_config = of_find_node_by_phandle(be32_to_cpup(phandle)); // 解析配置信息,并将结果存储到组的数据数组中 ret = pinconf_generic_parse_dt_config(np_config, NULL, &grp->data[j].configs, &grp->data[j].nconfigs); if (ret) return ret; }
// drivers/pinctrl/core.c /** * pinctrl_register() - register a pin controller device * @pctldesc: descriptor for this pin controller * @dev: parent device for this pin controller * @driver_data: private pin controller data for this pin controller * * Note that pinctrl_register() is known to have problems as the pin * controller driver functions are called before the driver has a * struct pinctrl_dev handle. To avoid issues later on, please use the * new pinctrl_register_and_init() below instead. */ struct pinctrl_dev *pinctrl_register(struct pinctrl_desc *pctldesc, struct device *dev, void *driver_data) { structpinctrl_dev *pctldev; int error; // 初始化 pinctrl 控制器 pctldev = pinctrl_init_controller(pctldesc, dev, driver_data); if (IS_ERR(pctldev)) return pctldev; // 启用 pinctrl 控制器 error = pinctrl_enable(pctldev); if (error) return ERR_PTR(error);
/* check core ops for sanity */ /* 检查核心操作函数的有效性 */ ret = pinctrl_check_ops(pctldev); if (ret) { dev_err(dev, "pinctrl ops lacks necessary functions\n"); goto out_err; }
/* If we're implementing pinmuxing, check the ops for sanity */ /* 如果实现了引脚复用功能,检查操作函数的有效性 */ if (pctldesc->pmxops) { ret = pinmux_check_ops(pctldev); if (ret) goto out_err; }
/* If we're implementing pinconfig, check the ops for sanity */ /* 如果实现了引脚配置功能,检查操作函数的有效性 */ if (pctldesc->confops) { ret = pinconf_check_ops(pctldev); if (ret) goto out_err; }
/* Register all the pins */ /* 注册所有引脚 */ dev_dbg(dev, "try to register %d pins ...\n", pctldesc->npins); ret = pinctrl_register_pins(pctldev, pctldesc->pins, pctldesc->npins); if (ret) { dev_err(dev, "error during pin registration\n"); pinctrl_free_pindescs(pctldev, pctldesc->pins, pctldesc->npins); goto out_err; }
/** * 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 * @link_consumers: If true create a device link between pinctrl and its * consumers (i.e. the devices requesting pin control states). This is * sometimes necessary to ascertain the right suspend/resume order for * example. */ structpinctrl_desc { constchar *name;// 引脚控制器的名称 conststructpinctrl_pin_desc *pins;// 引脚描述符数组 unsignedint npins;// 引脚描述符数组的大小 conststructpinctrl_ops *pctlops;// 引脚控制操作函数指针 conststructpinmux_ops *pmxops;// 引脚复用操作函数指针 conststructpinconf_ops *confops;// 引脚配置操作函数指针 structmodule *owner;// 拥有该结构体的模块 #ifdef CONFIG_GENERIC_PINCONF unsignedint num_custom_params;// 自定义参数数量 conststructpinconf_generic_params *custom_params;// 自定义参数数组 conststructpin_config_item *custom_conf_items;// 自定义配置项数组 #endif bool link_consumers; };
structrockchip_pin_ctrl { structrockchip_pin_bank *pin_banks;// 引脚bank的数组指针 u32 nr_banks;// pin_bank的数量 u32 nr_pins;// 引脚的数量 char *label;// 引脚控制器标签 enumrockchip_pinctrl_typetype;// 引脚控制器的类型 int grf_mux_offset;// GRF(Global Register File)复用寄存器的偏移量 int pmu_mux_offset;// PMU(电源管理单元)复用寄存器的偏移量 int grf_drv_offset;// GRF驱动寄存器的偏移量 int pmu_drv_offset; structrockchip_mux_recalced_data *iomux_recalced; u32 niomux_recalced; structrockchip_mux_route_data *iomux_routes; u32 niomux_routes;
int (*pull_calc_reg)(struct rockchip_pin_bank *bank, int pin_num, struct regmap **regmap, int *reg, u8 *bit); int (*drv_calc_reg)(struct rockchip_pin_bank *bank, int pin_num, struct regmap **regmap, int *reg, u8 *bit); int (*schmitt_calc_reg)(struct rockchip_pin_bank *bank, int pin_num, struct regmap **regmap, int *reg, u8 *bit); int (*slew_rate_calc_reg)(struct rockchip_pin_bank *bank, int pin_num, struct regmap **regmap, int *reg, u8 *bit); };
/** * 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 */ structpinctrl_dev { structlist_headnode;// pinctrl_dev链表中的节点 structpinctrl_desc *desc;// 引脚控制器描述指针 structradix_tree_rootpin_desc_tree;// 引脚描述结构体的radix树 #ifdef CONFIG_GENERIC_PINCTRL_GROUPS structradix_tree_rootpin_group_tree;// 引脚组结构体的radix树根 unsignedint num_groups;// 引脚组的数量 #endif #ifdef CONFIG_GENERIC_PINMUX_FUNCTIONS structradix_tree_rootpin_function_tree;// 引脚功能结构体的radix树根 unsignedint num_functions;// 引脚功能的数量 #endif structlist_headgpio_ranges;// GPIO范围链表 structdevice *dev;// 设备结构体指针 structmodule *owner;// 拥有pinctrl_dev结构体的模块的指针 void *driver_data;// 驱动程序的私有数据指针 structpinctrl *p;// pinctrl结构体指针 structpinctrl_state *hog_default;// hog默认状态 structpinctrl_state *hog_sleep;// hog睡眠状态 structmutexmutex;// 互斥锁 #ifdef CONFIG_DEBUG_FS structdentry *device_root;// 调试文件系统的根节点 #endif };
/** * 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. */ structpinctrl_ops { int (*get_groups_count) (struct pinctrl_dev *pctldev);//获取指定的 Pin Control 设备支持的引脚组数量 constchar *(*get_group_name) (struct pinctrl_dev *pctldev, unsigned selector);// 获取指定引脚组选择器对应的引脚组名称 int (*get_group_pins) (struct pinctrl_dev *pctldev, unsigned selector, constunsigned **pins, unsigned *num_pins);// 获取指定引脚组选择器对应的引脚组中的引脚列表 void (*pin_dbg_show) (struct pinctrl_dev *pctldev, struct seq_file *s, unsigned offset);//在调试信息中输出指定引脚选择器对应的引脚信息 int (*dt_node_to_map) (struct pinctrl_dev *pctldev, struct device_node *np_config, struct pinctrl_map **map, unsigned *num_maps);// 根据给定的设备树节点,创建与之相关联的 Pin Control 映射 void (*dt_free_map) (struct pinctrl_dev *pctldev, struct pinctrl_map *map, unsigned num_maps);//释放之前通过 dt_node_to_map 创建的Pin Control 映射 };
// include/linux/pinctrl/machine.h /** * 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 */ structpinctrl_map { constchar *dev_name;// 设备名称 constchar *name;// 映射名称 enumpinctrl_map_typetype;// 映射类型 constchar *ctrl_dev_name;// 控制设备名称 union { structpinctrl_map_muxmux;// 复用映射数据 structpinctrl_map_configsconfigs;// 配置映射数据 } data; };
/* * first find the group of this node and check if we need to create * config maps for pins */ /* 查找引脚组 */ grp = pinctrl_name_to_group(info, np->name);// 根据节点名称查找对应的引脚组 if (!grp) {// 如果找不到引脚组,打印错误信息 dev_err(dev, "unable to find group for node %pOFn\n", np); return -EINVAL; }
map_num += grp->npins;// 计算映射数量,包括复用映射和配置映射
new_map = kcalloc(map_num, sizeof(*new_map), GFP_KERNEL);// 分配内存空间用于存储映射数组 if (!new_map) return -ENOMEM;
/** * 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. * @strict: do not allow simultaneous use of the same pin for GPIO and another * function. Check both gpio_owner and mux_owner strictly before approving * the pin request. */ structpinmux_ops { // 查看是否可以将某个引脚设置为可用于复用 int (*request) (struct pinctrl_dev *pctldev, unsigned offset); // request() 回调的反向函数,在请求后释放引脚 int (*free) (struct pinctrl_dev *pctldev, unsigned offset); // 返回此 Pinmux 驱动程序中可选择的命名函数数量 int (*get_functions_count) (struct pinctrl_dev *pctldev); // 返回复用选择器的函数名称,核心调用此函数来确定应将某个设备映射到哪个复用设置 constchar *(*get_function_name) (struct pinctrl_dev *pctldev, unsigned selector); // 返回与某个函数选择器相关联的一组组名称(依次引用引脚) int (*get_function_groups) (struct pinctrl_dev *pctldev, unsigned selector, constchar * const **groups, unsigned *num_groups); // 使用特定引脚组启用特定复用功能 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); // 在特定引脚上释放 GPIO 复用 void (*gpio_disable_free) (struct pinctrl_dev *pctldev, struct pinctrl_gpio_range *range, unsigned offset); // 根据 GPIO 配置为输入或输出而进行不同的配置 int (*gpio_set_direction) (struct pinctrl_dev *pctldev, struct pinctrl_gpio_range *range, unsigned offset, bool input); // 不允许将同一引脚同时用于 GPIO 和其他功能。在批准引脚请求之前,严格检查 gpio_owner 和 mux_owner bool strict; };
dev_dbg(dev, "enable function %s group %s\n", info->functions[selector].name, info->groups[group].name);
/* * for each pin in the pin group selected, program the corresponding * pin function number in the config register. */ /* * 针对所选的引脚组中的每个引脚,将相应的引脚功能号码编程到配置寄存器中。 */ for (cnt = 0; cnt < info->groups[group].npins; cnt++) { bank = pin_to_bank(info, pins[cnt]); ret = rockchip_set_mux(bank, pins[cnt] - bank->pin_base, data[cnt].func); if (ret) break; }
if (ret && cnt) { /* revert the already done pin settings */ /* 恢复已经设置的引脚设置 */ for (cnt--; cnt >= 0 && !data[cnt].func; cnt--) rockchip_set_mux(bank, pins[cnt] - bank->pin_base, 0);
/** * 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; should * return -ENOTSUPP and -EINVAL using the same rules as pin_config_get. * @pin_config_group_set: configure all pins in a group * @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 */ structpinconf_ops { #ifdef CONFIG_GENERIC_PINCONF bool is_generic;// 是否为通用引脚配置操作 #endif // 获取引脚配置信息 int (*pin_config_get) (struct pinctrl_dev *pctldev, unsigned pin, unsignedlong *config); // 设置引脚配置信息 int (*pin_config_set) (struct pinctrl_dev *pctldev, unsigned pin, unsignedlong *configs, unsigned num_configs); // 获取引脚组配置信息 int (*pin_config_group_get) (struct pinctrl_dev *pctldev, unsigned selector, unsignedlong *config); // 设置引脚组配置信息 int (*pin_config_group_set) (struct pinctrl_dev *pctldev, unsigned selector, unsignedlong *configs, unsigned num_configs); // 调试函数,显示引脚配置信息 void (*pin_config_dbg_show) (struct pinctrl_dev *pctldev, struct seq_file *s, unsigned offset);
/* get the pin config settings for a specified pin */ staticintrockchip_pinconf_get(struct pinctrl_dev *pctldev, unsignedint pin, unsignedlong *config) { structrockchip_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); structrockchip_pin_bank *bank = pin_to_bank(info, pin); structgpio_chip *gpio = &bank->gpio_chip; enumpin_config_paramparam = pinconf_to_config_param(*config); u16 arg; int rc;
switch (param) { case PIN_CONFIG_BIAS_DISABLE:// 检查上下拉电阻是否禁用 if (rockchip_get_pull(bank, pin - bank->pin_base) != param) return -EINVAL;
arg = 0; break; case PIN_CONFIG_BIAS_PULL_UP: case PIN_CONFIG_BIAS_PULL_DOWN: case PIN_CONFIG_BIAS_PULL_PIN_DEFAULT: case PIN_CONFIG_BIAS_BUS_HOLD:// 检查上下拉电阻是否有效,并获取当前的上下拉电阻配置 if (!rockchip_pinconf_pull_valid(info->ctrl, param)) return -ENOTSUPP;
if (rockchip_get_pull(bank, pin - bank->pin_base) != param) return -EINVAL;
/* set the pin config settings for a specified pin */ staticintrockchip_pinconf_set(struct pinctrl_dev *pctldev, unsignedint pin, unsignedlong *configs, unsigned num_configs) { structrockchip_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); structrockchip_pin_bank *bank = pin_to_bank(info, pin); structgpio_chip *gpio = &bank->gpio_chip; enumpin_config_paramparam; u32 arg; int i; int rc;
for (i = 0; i < num_configs; i++) { param = pinconf_to_config_param(configs[i]); arg = pinconf_to_config_argument(configs[i]);
if (param == PIN_CONFIG_OUTPUT || param == PIN_CONFIG_INPUT_ENABLE) { /* * Check for gpio driver not being probed yet. * The lock makes sure that either gpio-probe has completed * or the gpio driver hasn't probed yet. */ /* * 检查 GPIO 驱动程序是否已经探测到。 * 锁定确保 GPIO 探测完成或者 GPIO 驱动程序尚未探测到。 */ mutex_lock(&bank->deferred_lock); if (!gpio || !gpio->direction_output) { // 如果驱动程序尚未探测到,则将配置信息延迟处理并返回。 rc = rockchip_pinconf_defer_pin(bank, pin - bank->pin_base, param, arg); mutex_unlock(&bank->deferred_lock); if (rc) return rc;
break; } mutex_unlock(&bank->deferred_lock); }
switch (param) { case PIN_CONFIG_BIAS_DISABLE: // 禁用上下拉电阻 rc = rockchip_set_pull(bank, pin - bank->pin_base, param); if (rc) return rc; break; case PIN_CONFIG_BIAS_PULL_UP: case PIN_CONFIG_BIAS_PULL_DOWN: case PIN_CONFIG_BIAS_PULL_PIN_DEFAULT: case PIN_CONFIG_BIAS_BUS_HOLD: // 检查上下拉电阻是否有效 if (!rockchip_pinconf_pull_valid(info->ctrl, param)) return -ENOTSUPP;
if (!arg) return -EINVAL; // 设置上下拉电阻 rc = rockchip_set_pull(bank, pin - bank->pin_base, param); if (rc) return rc; break; case PIN_CONFIG_OUTPUT: // 设置引脚复用功能为 GPIO rc = rockchip_set_mux(bank, pin - bank->pin_base, RK_FUNC_GPIO); if (rc != RK_FUNC_GPIO) return -EINVAL; // 设置引脚为输出模式 rc = gpio->direction_output(gpio, pin - bank->pin_base, arg); if (rc) return rc; break; case PIN_CONFIG_INPUT_ENABLE: // 设置引脚复用功能为 GPIO rc = rockchip_set_mux(bank, pin - bank->pin_base, RK_FUNC_GPIO); if (rc != RK_FUNC_GPIO) return -EINVAL; // 设置引脚为输入模式 rc = gpio->direction_input(gpio, pin - bank->pin_base); if (rc) return rc; break; case PIN_CONFIG_DRIVE_STRENGTH: /* rk3288 is the first with per-pin drive-strength */ // 仅支持某些芯片(如 rk3288)的每个引脚独立的驱动强度设置 if (!info->ctrl->drv_calc_reg) return -ENOTSUPP; // 设置引脚的驱动强度 rc = rockchip_set_drive_perpin(bank, pin - bank->pin_base, arg); if (rc < 0) return rc; break; case PIN_CONFIG_INPUT_SCHMITT_ENABLE: // 仅支持某些芯片的施密特触发设置 if (!info->ctrl->schmitt_calc_reg) return -ENOTSUPP; // 设置引脚的施密特触发模式 rc = rockchip_set_schmitt(bank, pin - bank->pin_base, arg); if (rc < 0) return rc; break; case PIN_CONFIG_SLEW_RATE: // 仅支持某些芯片的引脚驱动速率设置 if (!info->ctrl->slew_rate_calc_reg) return -ENOTSUPP; // 设置引脚的驱动速率 rc = rockchip_set_slew_rate(bank, pin - bank->pin_base, arg); if (rc < 0) return rc; break; default:// 不支持的配置参数 return -ENOTSUPP; } } /* for each config */
staticintreally_probe(struct device *dev, struct device_driver *drv) { int ret = -EPROBE_DEFER; int local_trigger_count = atomic_read(&deferred_trigger_count); bool test_remove = IS_ENABLED(CONFIG_DEBUG_TEST_DRIVER_REMOVE) && !drv->suppress_bind_attrs;
if (defer_all_probes) { /* * Value of defer_all_probes can be set only by * device_block_probing() which, in turn, will call * wait_for_device_probe() right after that to avoid any races. */ dev_dbg(dev, "Driver %s force probe deferral\n", drv->name); driver_deferred_probe_add(dev); return ret; }
ret = device_links_check_suppliers(dev); if (ret == -EPROBE_DEFER) driver_deferred_probe_add_trigger(dev, local_trigger_count); if (ret) return ret;
atomic_inc(&probe_count); pr_debug("bus: '%s': %s: probing driver %s with device %s\n", drv->bus->name, __func__, drv->name, dev_name(dev)); if (!list_empty(&dev->devres_head)) { dev_crit(dev, "Resources present before probing\n"); ret = -EBUSY; goto done; }
re_probe: dev->driver = drv;// 将设备的驱动程序指针设置为当前驱动
/* If using pinctrl, bind pins now before probing */ /* 如果使用了 pinctrl,在探测之前绑定引脚 */ ret = pinctrl_bind_pins(dev);// 绑定设备的引脚 if (ret) goto pinctrl_bind_failed;
if (dev->bus->dma_configure) {// 配置 DMA ret = dev->bus->dma_configure(dev); if (ret) goto probe_failed; }
ret = driver_sysfs_add(dev);// 添加驱动程序的 sysfs 接口 if (ret) { pr_err("%s: driver_sysfs_add(%s) failed\n", __func__, dev_name(dev)); goto probe_failed; }
if (dev->pm_domain && dev->pm_domain->activate) { ret = dev->pm_domain->activate(dev);// 激活电源管理域 if (ret) goto probe_failed; }
if (dev->bus->probe) { ret = dev->bus->probe(dev);// 如果总线的探测函数存在,则调用总线的探测函数 if (ret) goto probe_failed; } elseif (drv->probe) { ret = drv->probe(dev);// 否则调用驱动程序的探测函数 if (ret) goto probe_failed; }
ret = device_add_groups(dev, drv->dev_groups); if (ret) { dev_err(dev, "device_add_groups() failed\n"); goto dev_groups_failed; }
if (dev_has_sync_state(dev)) { ret = device_create_file(dev, &dev_attr_state_synced); if (ret) { dev_err(dev, "state_synced sysfs add failed\n"); goto dev_sysfs_state_synced_failed; } }
switch (ret) { case -EPROBE_DEFER: /* Driver requested deferred probing */ dev_dbg(dev, "Driver %s requests probe deferral\n", drv->name); driver_deferred_probe_add_trigger(dev, local_trigger_count); break; case -ENODEV: case -ENXIO: pr_debug("%s: probe of %s rejects match %d\n", drv->name, dev_name(dev), ret); break; default: /* driver matched but the probe failed */ pr_warn("%s: probe of %s failed with error %d\n", drv->name, dev_name(dev), ret); } /* * Ignore errors returned by ->probe so that the next driver can try * its luck. */ ret = 0; done:// 执行完成后的处理逻辑 atomic_dec(&probe_count); wake_up_all(&probe_waitqueue); return ret; }
/** * pinctrl_bind_pins() - called by the device core before probe * @dev: the device that is just about to probe */ intpinctrl_bind_pins(struct device *dev) { int ret; // 检查设备是否重用了节点 if (dev->of_node_reused) return0; // 为设备的引脚分配内存空间 dev->pins = devm_kzalloc(dev, sizeof(*(dev->pins)), GFP_KERNEL); if (!dev->pins) return -ENOMEM; // 获取设备的 pinctrl 句柄 dev->pins->p = devm_pinctrl_get(dev); if (IS_ERR(dev->pins->p)) { dev_dbg(dev, "no pinctrl handle\n"); ret = PTR_ERR(dev->pins->p); goto cleanup_alloc; } // 查找设备的默认 pinctrl 状态 dev->pins->default_state = pinctrl_lookup_state(dev->pins->p, PINCTRL_STATE_DEFAULT); if (IS_ERR(dev->pins->default_state)) { dev_dbg(dev, "no default pinctrl state\n"); ret = 0; goto cleanup_get; } // 查找设备的初始化 pinctrl 状态 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"); // 选择默认的 pinctrl 状态 ret = pinctrl_select_state(dev->pins->p, dev->pins->default_state); } else { // 选择初始化的 pinctrl 状态 ret = pinctrl_select_state(dev->pins->p, dev->pins->init_state); }
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> */ /* * 如果启用了电源管理,我们还会寻找可选的睡眠和空闲的引脚状态,其语义在 * <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
return0;
/* * 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. */ /* 如果对于此设备没有找到 pinctrl 句柄或默认状态, * 让我们明确释放设备中的引脚容器,因为保留它没有意义。 */ 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 */ /* 我们忽略诸如 -ENOENT 的错误,表示没有 pinctrl 状态 */ return0; }
constchar *init_name; /* initial name of the device */// 设备的初始名称 conststructdevice_type *type;// 设备类型
structbus_type *bus;/* type of bus device is on */// 设备所在的总线类型 structdevice_driver *driver;/* which driver has allocated this device */// 分配该设备的驱动程序 void *platform_data; /* Platform specific data, device core doesn't touch it */// 平台特定的数据,设备核心不会修改它 void *driver_data; /* Driver data, set and get with dev_set_drvdata/dev_get_drvdata */// 驱动程序的数据,使用 dev_set/get_drvdata 来设置和获取 #ifdef CONFIG_PROVE_LOCKING structmutexlockdep_mutex; #endif structmutexmutex;/* mutex to synchronize calls to* its driver.*/
/** * 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 * @init_state: the state at probe time, if found * @sleep_state: the state at suspend time, if found * @idle_state: the state at idle (runtime suspend) time, if found */ structdev_pin_info { structpinctrl *p;// 引脚控制器指针 structpinctrl_state *default_state;// 默认状态指针 structpinctrl_state *init_state;// 初始化状态指针 #ifdef CONFIG_PM structpinctrl_state *sleep_state;// 睡眠状态指针 仅在支持电源管理时可用 structpinctrl_state *idle_state;// 空闲状态指针 仅在支持电源管理时可用 #endif };
// drivers/pinctrl/core.c /** * devm_pinctrl_get() - Resource managed pinctrl_get() * @dev: the device to obtain the handle for * * If there is a need to explicitly destroy the returned struct pinctrl, * devm_pinctrl_put() should be used, rather than plain pinctrl_put(). */ struct pinctrl *devm_pinctrl_get(struct device *dev) { structpinctrl **ptr, *p; // 为存储引脚控制器句柄的指针分配内存 ptr = devres_alloc(devm_pinctrl_release, sizeof(*ptr), GFP_KERNEL); if (!ptr) return ERR_PTR(-ENOMEM); // 获取设备的引脚控制器句柄 p = pinctrl_get(dev); if (!IS_ERR(p)) { // 如果获取成功,将引脚控制器句柄存储在指针中 *ptr = p; // 将指针添加到设备资源中 devres_add(dev, ptr); } else { // 如果获取失败,释放之前分配的指针内存 devres_free(ptr); }
// drivers/pinctrl/core.c /** * pinctrl_get() - retrieves the pinctrl handle for a device * @dev: the device to obtain the handle for */ struct pinctrl *pinctrl_get(struct device *dev) { structpinctrl *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) { dev_dbg(dev, "obtain a copy of previously claimed pinctrl\n"); kref_get(&p->users); return p; } // 创建并返回设备的引脚控制器句柄 return create_pinctrl(dev, NULL); } EXPORT_SYMBOL_GPL(pinctrl_get);
/* * 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() */ /* * 为每个映射创建状态 cookie 持有者 struct pinctrl。 * 这是当使用 pinctrl_get() 请求引脚控制句柄时消费者将获得的对象。 */ p = kzalloc(sizeof(*p), GFP_KERNEL); if (!p) return ERR_PTR(-ENOMEM); p->dev = dev; INIT_LIST_HEAD(&p->states); INIT_LIST_HEAD(&p->dt_maps);
ret = pinctrl_dt_to_map(p, pctldev); 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; /* * If pctldev is not null, we are claiming hog for it, * that means, setting that is served by pctldev by itself. * * Thus we must skip map that is for this device but is served * by other device. */ /* * 如果 pctldev 不为空,我们正在声明它的独占使用权, * 这意味着它自己提供了该设置。 * * 因此,我们必须跳过适用于此设备但由其他设备提供的映射。 */ if (pctldev && strcmp(dev_name(pctldev->dev), map->ctrl_dev_name)) continue;
ret = add_setting(p, pctldev, 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. */ /* * 在这一点上,添加设置可能会导致: * * - 延迟,如果引脚控制设备尚不可用 * - 失败,如果引脚控制设备尚不可用, * 并且该设置是一个独占设置。我们不能推迟它,因为 * 该独占设置会在设备注册后立即生效。 * * 如果返回的错误不是 -EPROBE_DEFER,则我们将 * 累积错误,以查看是否最终得到 -EPROBE_DEFER, * 因为那是最糟糕的情况。 */ 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 occurred, 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);
/** * struct pinctrl - per-device pin control state holder * @node: global list node * @dev: the device using this pin control handle * @states: a list of states for this device * @state: the current state * @dt_maps: the mapping table chunks dynamically parsed from device tree for * this device, if any * @users: reference count */ structpinctrl { structlist_headnode;// 用于将引脚控制器添加到全局列表的链表节点 structdevice *dev;// 关联的设备 structlist_headstates;// 存储引脚配置状态的链表,用于跟踪不同的引脚配置状态 structpinctrl_state *state;// 当前应用的引脚配置状态 structlist_headdt_maps;// 存储设备树中定义的引脚映射信息的链表 structkrefusers;// 引脚控制器的引用计数,用于跟踪引脚控制器的引用数量 };
/** * struct pinctrl_maps - a list item containing part of the mapping table * @node: mapping table list node * @maps: array of mapping table entries * @num_maps: the number of entries in @maps */ structpinctrl_maps { structlist_headnode;// 引脚控制器映射链表节点,用于将该映射添加到全局列表 conststructpinctrl_map *maps;// 指向引脚控制器映射数组的指针 unsigned num_maps; // 引脚控制器映射数组中的映射数量 };
/* CONFIG_OF enabled, p->dev not instantiated from DT */ /* 如果 CONFIG_OF 启用,且 p->dev 不是从设备树实例化而来 */ if (!np) { if (of_have_populated_dt()) dev_dbg(p->dev, "no of_node; not parsing pinctrl DT\n"); return0; }
/* We may store pointers to property names within the node */ /* 节点内部存储属性名称的指针 */ of_node_get(np);//增加设备树节点的引用计数,以确保在解析过程中节点不会被释放
/* For each defined state ID */ /* 对于每个定义的状态 ID */ for (state = 0; ; state++) { /* Retrieve the pinctrl-* property */ /* 获取 pinctrl-* 属性 */ propname = kasprintf(GFP_KERNEL, "pinctrl-%d", state); if (!propname) return -ENOMEM; prop = of_find_property(np, propname, &size); kfree(propname); if (!prop) { if (state == 0) { of_node_put(np); return -ENODEV; } break; } list = prop->value; size /= sizeof(*list);
/* Determine whether pinctrl-names property names the state */ /* 判断 pinctrl-names 属性是否命名了该状态 */ ret = of_property_read_string_index(np, "pinctrl-names", state, &statename); /* * If not, statename is just the integer state ID. But rather * than dynamically allocate it and have to free it later, * just point part way into the property name for the string. */ /* * 如果未命名,则 statename 仅是整数状态 ID。但是,为了避免动态分配和之后要释放的麻烦, * 可以直接将 statename 指向属性名称的一部分。 */ if (ret < 0) statename = prop->name + strlen("pinctrl-");
/* 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, pctldev, statename, np_config); of_node_put(np_config); if (ret < 0) goto err; }
/* No entries in DT? Generate a dummy state table entry */ /* 如果在设备树中没有条目,则生成一个虚拟状态表条目 */ if (!size) { ret = dt_remember_dummy_state(p, statename); if (ret < 0) goto err; } }
/** * pinctrl_register_mappings() - register a set of pin controller mappings * @maps: the pincontrol mappings table to register. Note the pinctrl-core * keeps a reference to the passed in maps, so they should _not_ be * marked with __initdata. * @num_maps: the number of maps in the mapping table */ // maps 指向映射表条目数组的指针 // num_maps 映射表条目数量 intpinctrl_register_mappings(conststruct pinctrl_map *maps, unsigned num_maps) { int i, ret; structpinctrl_maps *maps_node;
pr_debug("add %u pinctrl maps\n", num_maps);
/* First sanity check the new mapping */ /* 首先对新映射表进行合法性检查 */ for (i = 0; i < num_maps; i++) { // 检查设备名称是否存在 if (!maps[i].dev_name) { pr_err("failed to register map %s (%d): no device given\n", maps[i].name, i); return -EINVAL; } // 检查映射表名称是否存在 if (!maps[i].name) { pr_err("failed to register map %d: no map name given\n", i); return -EINVAL; } // 对于引脚映射类型和配置映射类型,检查引脚控制设备名称是否存在 if (maps[i].type != PIN_MAP_TYPE_DUMMY_STATE && !maps[i].ctrl_dev_name) { pr_err("failed to register map %s (%d): no pin control device given\n", maps[i].name, i); return -EINVAL; }
switch (maps[i].type) { case PIN_MAP_TYPE_DUMMY_STATE:// 对于虚拟状态映射类型,不进行验证 break; case PIN_MAP_TYPE_MUX_GROUP:// 对于复用组映射类型,进行引脚复用映射验证 ret = pinmux_validate_map(&maps[i], i); if (ret < 0) return ret; break; case PIN_MAP_TYPE_CONFIGS_PIN: case PIN_MAP_TYPE_CONFIGS_GROUP:// 对于配置映射类型,进行引脚配置映射验证 ret = pinconf_validate_map(&maps[i], i); if (ret < 0) return ret; break; default:// 对于无效的映射类型,返回错误 pr_err("failed to register map %s (%d): invalid type given\n", maps[i].name, i); return -EINVAL; } } // 分配映射表节点内存 maps_node = kzalloc(sizeof(*maps_node), GFP_KERNEL); if (!maps_node) return -ENOMEM; // 设置映射表节点的映射表和映射表数量 maps_node->maps = maps; maps_node->num_maps = num_maps; // 加锁并将映射表节点插入映射表链表末尾 mutex_lock(&pinctrl_maps_mutex); list_add_tail(&maps_node->node, &pinctrl_maps); mutex_unlock(&pinctrl_maps_mutex);
if (pctldev)// 设置pinctrl_setting的引脚控制设备 setting->pctldev = pctldev; else setting->pctldev = get_pinctrl_dev_from_devname(map->ctrl_dev_name); if (!setting->pctldev) { 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; } // 设置pinctrl_setting的设备名称 setting->dev_name = map->dev_name;
switch (map->type) { case PIN_MAP_TYPE_MUX_GROUP: // 对于复用组映射类型,执行pinctrl_map到pinctrl_setting的转换 ret = pinmux_map_to_setting(map, setting); break; case PIN_MAP_TYPE_CONFIGS_PIN: case PIN_MAP_TYPE_CONFIGS_GROUP: // 对于配置映射类型,执行pinctrl_map到pinctrl_setting的转换 ret = pinconf_map_to_setting(map, setting); break; default: ret = -EINVAL; break; } if (ret < 0) { kfree(setting); return ret; } // 将pinctrl_setting插入状态对象的设置链表末尾 list_add_tail(&setting->node, &state->settings);
/** * 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 */ structpinctrl_state { structlist_headnode;// 链表节点,用于将状态对象连接到引脚控制器对象的状态链表 constchar *name;// 状态对象的名称字符串指针 structlist_headsettings;// pinctrl_setting对象链表,包含该状态的所有设置对象 };
// drivers/pinctrl/core.h /** * struct pinctrl_setting - an individual mux or config setting * @node: list node for struct pinctrl_settings's @settings field * @type: the type of setting * @pctldev: pin control device handling to be programmed. Not used for * PIN_MAP_TYPE_DUMMY_STATE. * @dev_name: the name of the device using this state * @data: Data specific to the setting type */ structpinctrl_setting { structlist_headnode;// 链表节点,用于将设置对象连接到状态对象的设置链表 enumpinctrl_map_typetype;// 映射类型,表示设置对象的类型 structpinctrl_dev *pctldev;// 引脚控制设备对象指针 constchar *dev_name; // 设备名称字符串指针 union { structpinctrl_setting_muxmux;// 复用组映射类型的数据结构 structpinctrl_setting_configsconfigs;// 配置映射类型的数据结构 } data; };
create_state()
add_setting()函数中,根据映射表条目的名称,使用 find_state() 函数在引脚控制器对象中查找对应的状态对象,在此之前我们并没有设置状态对象,所以会进入到第二个 if 判断,通过state = create_state(p, map->name)创建一个state
/** * pinctrl_lookup_state() - retrieves a state handle from a pinctrl handle * @p: the pinctrl handle to retrieve the state from * @name: the state name to retrieve */ struct pinctrl_state *pinctrl_lookup_state(struct pinctrl *p, constchar *name) { structpinctrl_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 // 如果找不到指定的状态对象,并且不存在虚拟状态,则返回错误指针 -ENODEV state = ERR_PTR(-ENODEV); }
/** * pinctrl_select_state() - select/activate/program a pinctrl state to HW * @p: the pinctrl handle for the device that requests configuration * @state: the state handle to select/activate/program */ intpinctrl_select_state(struct pinctrl *p, struct pinctrl_state *state) { if (p->state == state)// 如果当前状态已经是要选择的状态,则无需进行任何操作,直接返回 0 表示成功 return0; // 调用 pinctrl_commit_state 函数来应用并切换到新的状态 return pinctrl_commit_state(p, state); } EXPORT_SYMBOL_GPL(pinctrl_select_state);
/** * pinctrl_commit_state() - select/activate/program a pinctrl state to HW * @p: the pinctrl handle for the device that requests configuration * @state: the state handle to select/activate/program */ staticintpinctrl_commit_state(struct pinctrl *p, struct pinctrl_state *state) { structpinctrl_setting *setting, *setting2; structpinctrl_state *old_state = p->state; int ret;
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. */ /* * 对于旧状态中的每个引脚复用设置,取消 SW 记录的该引脚组的复用所有者。 * 任何仍由新状态拥有的引脚组将在下面循环中的 pinmux_enable_setting() 调用中重新获取。 */ 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: // 对于引脚复用设置(PIN_MAP_TYPE_MUX_GROUP),调用 pinmux_enable_setting()函数来启用该设置。 ret = pinmux_enable_setting(setting); break; case PIN_MAP_TYPE_CONFIGS_PIN: case PIN_MAP_TYPE_CONFIGS_GROUP: // 对于引脚配置设置(PIN_MAP_TYPE_CONFIGS_PIN 或 PIN_MAP_TYPE_CONFIGS_GROUP),调用 pinconf_apply_setting()函数来应用该设置 ret = pinconf_apply_setting(setting); break; default: ret = -EINVAL; break; }
if (ret < 0) { // 如果应用设置失败,则回滚新状态的设置 goto unapply_new_state; }
/* Do not link hogs (circular dependency) */ if (p != setting->pctldev->p) pinctrl_link_add(setting->pctldev, p->dev); }
p->state = state;
return0;
unapply_new_state: // 回滚新状态的设置 dev_err(p->dev, "Error applying setting, reverse things back\n");
list_for_each_entry(setting2, &state->settings, node) { if (&setting2->node == &setting->node) break; /* * All we can do here is pinmux_disable_setting. * That means that some pins are muxed differently now * than they were before applying the setting (We can't * "unmux a pin"!), but it's not a big deal since the pins * are free to be muxed by another apply_setting. */ if (setting2->type == PIN_MAP_TYPE_MUX_GROUP) pinmux_disable_setting(setting2); }
/* There's no infinite recursive loop here because p->state is NULL */ if (old_state) pinctrl_select_state(p, old_state);
//drivers/pinctrl/pinmux.c intpinmux_enable_setting(conststruct pinctrl_setting *setting) { structpinctrl_dev *pctldev = setting->pctldev; conststructpinctrl_ops *pctlops = pctldev->desc->pctlops; conststructpinmux_ops *ops = pctldev->desc->pmxops; int ret = 0; constunsigned *pins = NULL; unsigned num_pins = 0; int i; structpin_desc *desc; // 如果 pctlops->get_group_pins 函数存在,则调用该函数获取组中的引脚信息,并将引脚信息存储在 pins 和 num_pins 变量中 if (pctlops->get_group_pins) ret = pctlops->get_group_pins(pctldev, setting->data.mux.group, &pins, &num_pins);
if (ret) {// 如果获取引脚信息失败,发出警告并将 num_pins 设置为 0 constchar *gname;
/* errors only affect debug data, so just warn */ // 错误只影响调试数据,因此只发出警告 gname = pctlops->get_group_name(pctldev, setting->data.mux.group); dev_warn(pctldev->dev, "could not get pins for group %s\n", gname); num_pins = 0; }
/* Try to allocate all pins in this group, one by one */ // 逐个申请组中的引脚 for (i = 0; i < num_pins; i++) { // 使用 pin_request 函数申请引脚,并传入引脚控制器设备、引脚编号、设备名称和其他参数 ret = pin_request(pctldev, pins[i], setting->dev_name, NULL); if (ret) { constchar *gname; constchar *pname; // 分配引脚后,使用 pin_desc_get 函数获取引脚描述符,并将复用设置指针指向引脚复用信息。 desc = pin_desc_get(pctldev, pins[i]); pname = desc ? desc->name : "non-existing"; gname = pctlops->get_group_name(pctldev, setting->data.mux.group); dev_err(pctldev->dev, "could not request pin %d (%s) from group %s " " on device %s\n", pins[i], pname, gname, pinctrl_dev_get_name(pctldev)); goto err_pin_request; } }
/* Now that we have acquired the pins, encode the mux setting */ // 分配引脚后,编码复用设置 for (i = 0; i < num_pins; i++) { desc = pin_desc_get(pctldev, pins[i]); if (desc == NULL) { dev_warn(pctldev->dev, "could not get pin desc for pin %d\n", pins[i]); continue; } desc->mux_setting = &(setting->data.mux); } // 调用 ops->set_mux 函数设置引脚复用,传入引脚控制器设备、复用功能和组信息,以便设置引脚复用。 ret = ops->set_mux(pctldev, setting->data.mux.func, setting->data.mux.group);
if (ret) goto err_set_mux;
return0;
err_set_mux: // 复用设置失败,清除复用设置 for (i = 0; i < num_pins; i++) { desc = pin_desc_get(pctldev, pins[i]); if (desc) desc->mux_setting = NULL; } err_pin_request: /* On error release all taken pins */ // 在错误发生时释放已申请的引脚 while (--i >= 0) pin_free(pctldev, pins[i], NULL);
/* CONFIG_OF enabled, p->dev not instantiated from DT */ /* 如果 CONFIG_OF 启用,且 p->dev 不是从设备树实例化而来 */ if (!np) { if (of_have_populated_dt()) dev_dbg(p->dev, "no of_node; not parsing pinctrl DT\n"); return0; }
/* We may store pointers to property names within the node */ /* 节点内部存储属性名称的指针 */ of_node_get(np);//增加设备树节点的引用计数,以确保在解析过程中节点不会被释放
/* For each defined state ID */ /* 对于每个定义的状态 ID */ for (state = 0; ; state++) { /* Retrieve the pinctrl-* property */ /* 获取 pinctrl-* 属性 */ propname = kasprintf(GFP_KERNEL, "pinctrl-%d", state); if (!propname) return -ENOMEM; prop = of_find_property(np, propname, &size); kfree(propname); if (!prop) { if (state == 0) { of_node_put(np); return -ENODEV; } break; } list = prop->value; size /= sizeof(*list);
/* Determine whether pinctrl-names property names the state */ /* 判断 pinctrl-names 属性是否命名了该状态 */ ret = of_property_read_string_index(np, "pinctrl-names", state, &statename); /* * If not, statename is just the integer state ID. But rather * than dynamically allocate it and have to free it later, * just point part way into the property name for the string. */ /* * 如果未命名,则 statename 仅是整数状态 ID。但是,为了避免动态分配和之后要释放的麻烦, * 可以直接将 statename 指向属性名称的一部分。 */ if (ret < 0) statename = prop->name + strlen("pinctrl-");
/* 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, pctldev, statename, np_config); of_node_put(np_config); if (ret < 0) goto err; }
/* No entries in DT? Generate a dummy state table entry */ /* 如果在设备树中没有条目,则生成一个虚拟状态表条目 */ if (!size) { ret = dt_remember_dummy_state(p, statename); if (ret < 0) goto err; } }