1. pinctrl device tree
    1. pinctrl driver
    2. groups and function
  2. Rockchip pinctrl related structure
    1. struct pinctrl_desc
    2. struct pinctrl_pin_desc
    3. struct pinctrl_dev
    4. struct rockchip_pinctrl
    5. struct rockchip_pin_ctrl
    6. struct rockchip_pin_bank
  3. rockchip_pinctrl_probe()
    1. Probe function mind map
    2. rockchip_pinctrl_get_soc_data()
    3. syscon
      1. Why is it needed compared to direct ioremap? syscon
      2. struct regmap
      3. syscon device tree
      4. Kernel API usage example
    4. rockchip_pinctrl_register()
      1. rockchip_pinctrl_parse_dt()
        1. rockchip_pinctrl_child_count()
        2. rockchip_pinctrl_parse_functions()
          1. rockchip_pinctrl_parse_groups()
      2. devm_pinctrl_register()
        1. pinctrl_register()
        2. pinctrl_init_controller()
  4. pinctrl subsystem function operation set
    1. pinctrl_ops
      1. get_groups_count
      2. get_group_name
      3. get_group_pins
      4. dt_node_to_map
        1. related structures
          1. struct pinctrl_map
          2. struct pinctrl_map_mux
          3. struct pinctrl_map_configs
        2. rockchip_dt_node_to_map()
      5. dt_free_map
    2. pinconf_ops
      1. pin_config_get
      2. pin_config_set
    3. pinmux_ops
      1. get_functions_count
      2. get_function_name
      3. get_function_groups
      4. set_mux
  • When is the pin multiplexing relationship set?
    1. really_probe()
    2. pinctrl_bind_pins()
      1. struct dev_pin_info
      2. devm_pinctrl_get()
      3. pinctrl_get()
      4. create_pinctrl()
        1. Important data structures
          1. struct pinctrl
          2. struct pinctrl_maps
        2. pinctrl_dt_to_map()
          1. dt_to_map_one_config()
          2. dt_remember_or_free_map()
          3. struct pinctrl_dt_map
          4. pinctrl_register_mappings()
        3. add_setting()
          1. struct pinctrl_state
          2. struct pinctrl_setting
          3. create_state()
          4. pinmux_map_to_setting()
          5. pinconf_map_to_setting()
      5. pinctrl_lookup_state()
      6. pinctrl_select_state()
        1. pinctrl_commit_state()
          1. pinmux_enable_setting()
          2. pinconf_apply_setting()
    3. Mind map
    4. Conclusion
  • Cover image for Linux pinctrl subsystem

    Linux pinctrl subsystem

    Words 22k
    Views
    Visitors

    Timeline

    Timeline

    2025-12-16

    init

    This article introduces the description and driver implementation mechanism of the Linux pinctrl subsystem in the device tree. The article first explains the relationship between GPIO pins and SoC pins, pointing out that the GPIO controller is a child node of the pin controller, and uses RK3568 as an example to list the base addresses and resource composition of each GPIO bank. Subsequently, the article describes the matching method of the pinctrl driver, that is, finding the corresponding driver through the compatible attribute of the pinctrl node in the device tree, and points out that the driver is based on the platform bus. Then, it focuses on two key concepts in the pinctrl subsystem: pin groups and functions, and uses can0 and can1 as examples to explain in detail the configuration methods of pin groups under different controllers. Finally, the article introduces the core structures related to rockchip pinctrl, such as struct pinctrl_desc, including the roles of fields such as the pin controller name, pin descriptor array, pin control operation functions, pin multiplexing operation functions, and pin configuration operation functions.

    Linux Driver Notes

    Table of ContentsLinks
    1. Linux Driver Framework
    2. Linux Driver Loading Logic
    3. Character Device Basics
    4. Concurrency and Race Conditions
    5. Advanced Character Device Topics
    6. Interrupts
    7. Platform Bus
    8. Device Tree
    9. Device Model
    10. Hotplug
    11. pinctrl Subsystem
    12. GPIO subsystem
    13. Input subsystem
    14. 1-Wire
    15. I2C
    16. SPI
    17. UART
    18. PWM
    19. RTC
    20. Watchdog
    21. CAN
    22. Network devices
    23. ADC
    24. IIO
    25. USB
    26. LCD

    pinctrl device tree

    arch/arm64/boot/dts/rk3568.dtsi

    1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768
    pinctrl: pinctrl {	compatible = "rockchip,rk3568-pinctrl";	rockchip,grf = <&grf>;	rockchip,pmu = <&pmugrf>;	#address-cells = <2>;	#size-cells = <2>;	ranges;	gpio0: gpio0@fdd60000 {		compatible = "rockchip,gpio-bank";		reg = <0x0 0xfdd60000 0x0 0x100>;		interrupts = <GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>;		clocks = <&pmucru PCLK_GPIO0>, <&pmucru DBCLK_GPIO0>;		gpio-controller;		#gpio-cells = <2>;		interrupt-controller;		#interrupt-cells = <2>;	};	gpio1: gpio1@fe740000 {		compatible = "rockchip,gpio-bank";		reg = <0x0 0xfe740000 0x0 0x100>;		interrupts = <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>;		clocks = <&cru PCLK_GPIO1>, <&cru DBCLK_GPIO1>;		gpio-controller;		#gpio-cells = <2>;		interrupt-controller;		#interrupt-cells = <2>;	};	gpio2: gpio2@fe750000 {		compatible = "rockchip,gpio-bank";		reg = <0x0 0xfe750000 0x0 0x100>;		interrupts = <GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH>;		clocks = <&cru PCLK_GPIO2>, <&cru DBCLK_GPIO2>;		gpio-controller;		#gpio-cells = <2>;		interrupt-controller;		#interrupt-cells = <2>;	};	gpio3: gpio3@fe760000 {		compatible = "rockchip,gpio-bank";		reg = <0x0 0xfe760000 0x0 0x100>;		interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>;		clocks = <&cru PCLK_GPIO3>, <&cru DBCLK_GPIO3>;		gpio-controller;		#gpio-cells = <2>;		interrupt-controller;		#interrupt-cells = <2>;	};	gpio4: gpio4@fe770000 {		compatible = "rockchip,gpio-bank";		reg = <0x0 0xfe770000 0x0 0x100>;		interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>;		clocks = <&cru PCLK_GPIO4>, <&cru DBCLK_GPIO4>;		gpio-controller;		#gpio-cells = <2>;		interrupt-controller;		#interrupt-cells = <2>;	};};

    GPIO pins ⊂ SoC pins, and SoC pins are uniformly managed by pinctrl. The official Linux pinctrl binding recommends:GPIO controller as a child node of the pin controller

    GPIO bankNamePin countbase address
    GPIO0gpio0320xfdd60000
    GPIO1gpio1320xfe740000
    GPIO2gpio2320xfe750000
    GPIO3gpio3320xfe760000
    GPIO4gpio4320xfe770000

    Each bank:

    • A set of registers
    • One interrupt number
    • Two clocks (PCLK / DBCLK)
    • Controls a group of physical pins: direction, level, GPIO interrupt

    arch/arm64/boot/dts/rockchip/rk3568-pinctrl.dtsi

    12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667
    &pinctrl {	acodec {		/omit-if-no-ref/		acodec_pins: acodec-pins {			rockchip,pins =				/* acodec_adc_sync */				<1 RK_PB1 5 &pcfg_pull_none>,				/* acodec_adcclk */				<1 RK_PA1 5 &pcfg_pull_none>,				/* acodec_adcdata */				<1 RK_PA0 5 &pcfg_pull_none>,				/* acodec_dac_datal */				<1 RK_PA7 5 &pcfg_pull_none>,				/* acodec_dac_datar */				<1 RK_PB0 5 &pcfg_pull_none>,				/* acodec_dacclk */				<1 RK_PA3 5 &pcfg_pull_none>,				/* acodec_dacsync */				<1 RK_PA5 5 &pcfg_pull_none>;		};	};	audiopwm {		/omit-if-no-ref/		audiopwm_lout: audiopwm-lout {			rockchip,pins =				/* audiopwm_lout */				<1 RK_PA0 4 &pcfg_pull_none>;		};		/omit-if-no-ref/		audiopwm_loutn: audiopwm-loutn {			rockchip,pins =				/* audiopwm_loutn */				<1 RK_PA1 6 &pcfg_pull_none>;		};		/omit-if-no-ref/		audiopwm_loutp: audiopwm-loutp {			rockchip,pins =				/* audiopwm_loutp */				<1 RK_PA0 6 &pcfg_pull_none>;		};		/omit-if-no-ref/		audiopwm_rout: audiopwm-rout {			rockchip,pins =				/* audiopwm_rout */				<1 RK_PA1 4 &pcfg_pull_none>;		};		/omit-if-no-ref/		audiopwm_routn: audiopwm-routn {			rockchip,pins =				/* audiopwm_routn */				<1 RK_PA7 4 &pcfg_pull_none>;		};		/omit-if-no-ref/		audiopwm_routp: audiopwm-routp {			rockchip,pins =				/* audiopwm_routp */				<1 RK_PA6 4 &pcfg_pull_none>;		};	};    ...

    Whether it isrk3568.dtsiThe pinctrl node in the device tree, as above.rk3568-pinctrl.dtsiThe series of multiplexing relationships in the device tree are written by Rockchip’s original BSP engineers. We only need to know how to use them, while the pinctrl client device tree is written by ourselves according to specific requirements.

    pinctrl driver

    The device tree only stores descriptive information about the device, while the specific functional implementation depends on the corresponding pinctrl driver.

    According tork3568.dtsiThe compatible attribute of the pinctrl node in the device treeTo search for the driver, you can find that the pinctrl driver file is in the kernel source.drivers/pinctrl/pinctrl-rockchip.c

    12345678910111213141516171819202122232425262728293031
    static const struct of_device_id rockchip_pinctrl_dt_match[] = {...#ifdef CONFIG_CPU_RK3568	{ .compatible = "rockchip,rk3568-pinctrl",		.data = &rk3568_pin_ctrl },#endif...	{},};static struct platform_driver rockchip_pinctrl_driver = {	.probe		= rockchip_pinctrl_probe,	.remove		= rockchip_pinctrl_remove,	.driver = {		.name	= "rockchip-pinctrl",		.pm = &rockchip_pinctrl_dev_pm_ops,		.of_match_table = rockchip_pinctrl_dt_match,	},};static int __init rockchip_pinctrl_drv_register(void){	return platform_driver_register(&rockchip_pinctrl_driver);}postcore_initcall(rockchip_pinctrl_drv_register);static void __exit rockchip_pinctrl_drv_unregister(void){	platform_driver_unregister(&rockchip_pinctrl_driver);}module_exit(rockchip_pinctrl_drv_unregister);

    It can be seen that the pinctrl driver uses the platform bus, usingpostcore_initcallrather thanmodule_init

    groups and function

    In the pinctrl subsystem, there are two key concepts:Pin groups and Function

    • Pin groups: A pin group is a collection of pins that have similar functions, constraints, or work together. Each pin group is usually associated with a specific hardware function or peripheral. For example, one pin group can be used to control a serial communication interface (such as UART or SPI), and another pin group can be used to drive GPIO.
    • Function: Defines the functions on the chip that have peripheral functions. Each function node corresponds to the configuration information of one or more IO groups. These functions can be peripheral functions such as UART, SPI, I2C, etc.

    Next, takerk3568-pinctrl.dtsiin the device tree filecan0andcan1the two functions as examples to illustrate the above content, as shown below:

    123456789101112131415161718192021222324252627282930313233343536373839
    can0 {	/omit-if-no-ref/	can0m0_pins: can0m0-pins {		rockchip,pins =			/* can0_rxm0 */			<0 RK_PB4 2 &pcfg_pull_none>,			/* can0_txm0 */			<0 RK_PB3 2 &pcfg_pull_none>;	};	/omit-if-no-ref/	can0m1_pins: can0m1-pins {		rockchip,pins =			/* can0_rxm1 */			<2 RK_PA2 4 &pcfg_pull_none>,			/* can0_txm1 */			<2 RK_PA1 4 &pcfg_pull_none>;	};};can1 {	/omit-if-no-ref/	can1m0_pins: can1m0-pins {		rockchip,pins =			/* can1_rxm0 */			<1 RK_PA0 3 &pcfg_pull_none>,			/* can1_txm0 */			<1 RK_PA1 3 &pcfg_pull_none>;	};	/omit-if-no-ref/	can1m1_pins: can1m1-pins {		rockchip,pins =			/* can1_rxm1 */			<4 RK_PC2 3 &pcfg_pull_none>,			/* can1_txm1 */			<4 RK_PC3 3 &pcfg_pull_none>;	};};

    In the device tree above,can0 and can1 correspond to two different functionsrespectively the CAN0 controller and the CAN1 controllerEach controller also has two different groups (pin groups).

    • CAN0 controller:
      • Pin groupcan0m0-pins: This is the first pin group of the CAN0 controller, used to configure the pins of CAN0. It defines two pins:RK_PB4andRK_PB3
        • RK_PB4used for the receive pin of CAN0 (can0_rxm0
        • RK_PB3used for the transmit pin of CAN0 (can0_txm0)。
      • Pin groupcan0m1-pins: This is the second pin group of the CAN0 controller, also used to configure the pins of CAN0. It defines two pins:RK_PA2andRK_PA1
        • RK_PA2used for the receive pin of CAN0 (can0_rxm1
        • RK_PA1used for the transmit pin of CAN0 (can0_txm1)。
    • CAN1 controller:
      • Pin groupcan1m0-pins: This is the first pin group of the CAN1 controller, used to configure the pins of CAN1. It defines two pins:RK_PA0andRK_PA1
        • RK_PA0used for the receive pin of CAN1 (can1_rxm0
        • RK_PA1used for the transmit pin of CAN1 (can1_txm0)。
      • Pin groupcan1m1-pins: This is the second pin group of the CAN1 controller, also used to configure the pins of CAN1. It defines two pins:RK_PC2andRK_PC3
        • RK_PC2used for the receive pin of CAN1 (can1_rxm1
        • RK_PC3used for the transmit pin of CAN1 (can1_txm1)。

    Rockchip pinctrl related structure

    struct pinctrl_desc

    1234567891011121314151617181920212223242526272829303132333435363738394041
    /** * 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. */struct pinctrl_desc {	const char *name;// Name of the pin controller	const struct pinctrl_pin_desc *pins;// Pin descriptor array	unsigned int npins;// Size of the pin descriptor array	const struct pinctrl_ops *pctlops;// Pin control operation function pointer	const struct pinmux_ops *pmxops;// Pin multiplexing operation function pointer	const struct pinconf_ops *confops;// Pin configuration operation function pointer	struct module *owner;// Module that owns this structure#ifdef CONFIG_GENERIC_PINCONF	unsigned int num_custom_params;// Number of custom parameters	const struct pinconf_generic_params *custom_params;// Custom parameter array	const struct pin_config_item *custom_conf_items;// Custom configuration item array#endif	bool link_consumers;};
    • const char *name: Name of the pin controller, used to identify the uniqueness of the pin controller.

    • const struct pinctrl_pin_desc *pins: Pin descriptor array, is a pointer to a pin descriptor, used to describe the properties and configuration of the pin. Each pin descriptor contains information such as the pin’s name, number, and mode.

    • unsigned int npins: indicatesNumber of elements in the pin descriptor array, used to determine the length of the pin descriptor array.

    • const struct pinctrl_ops *pctlops: Pointer to the pin control operation function, used to define the operation interface of the pin controller. Through these operation functions, you canconfigure, enable, and disable the pinoperations, etc.

    • const struct pinmux_ops *pmxops: Pointer to the pin mux operation function, used to define the mux function of the pin. The mux function allowsswitching the pin’s function to different modes, to adapt to different device requirements

    • const struct pinconf_ops *confops: Pointer to the pin configuration operation function, used to define other configuration options for the pin.. These configuration options can includePin pull-up, pull-down configuration, electrical characteristics, etc.

    • struct module *owner: Pointer to the module that owns the pin controller structure. This field is used to track the owner of the pin controller structure.

    • unsigned int num_custom_params: Indicates the number of custom configuration parameters, used to describe the custom configuration parameters of the pin controller.

    • const struct pinconf_generic_params *custom_params: Pointer to custom configuration parameters, used to describe the attributes of the pin controller’s custom configuration parameters. Custom configuration parameters can be defined according to specific requirements to extend the configuration options of the pin controller.

    • const struct pin_config_item *custom_conf_items: Pointer to custom configuration items, used to describe the attributes of the pin controller’s custom configuration items. Custom configuration items can be defined according to specific requirements to extend the configuration options of the pin controller.

    struct pinctrl_pin_desc

    123456789101112
    /** * 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;};

    struct pinctrl_dev

    Beforerockchip_pinctrl_probeIn the function, throughinfo->pctl_dev = devm_pinctrl_register(dev, ctrldesc, info)Set

    1234567891011121314151617181920212223242526272829303132333435363738394041424344454647
    /** * 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;// Node in the pinctrl_dev linked list	struct pinctrl_desc *desc; // Pin controller description pointer	struct radix_tree_root pin_desc_tree;// Radix tree of pin description structures#ifdef CONFIG_GENERIC_PINCTRL_GROUPS	struct radix_tree_root pin_group_tree;// Radix tree root of pin group structures	unsigned int num_groups;// Number of pin groups#endif#ifdef CONFIG_GENERIC_PINMUX_FUNCTIONS	struct radix_tree_root pin_function_tree;// Radix tree root of pin function structures	unsigned int num_functions;// Number of pin functions#endif	struct list_head gpio_ranges;// GPIO range linked list	struct device *dev;// Device structure pointer	struct module *owner;// Pointer to the module that owns the pinctrl_dev structure	void *driver_data;// Driver's private data pointer	struct pinctrl *p;// pinctrl structure pointer	struct pinctrl_state *hog_default;// hog default state	struct pinctrl_state *hog_sleep;// hog sleep state	struct mutex mutex;// Mutex lock#ifdef CONFIG_DEBUG_FS	struct dentry *device_root;// Root node of the debug file system#endif};

    struct rockchip_pinctrl

    Rockchip, in order to adapt to the specific requirements and functions of Rockchip chips, hasstruct pinctrl_descperformed a re-encapsulation. The encapsulatedstruct rockchip_pinctrlThe structure isstruct pinctrl_descand adds fields and pointers related to Rockchip chips on this basis. This encapsulation provides better integration, usability, and extensibility while maintaining compatibility with the generic pin controller framework.

    1234567891011121314
    struct rockchip_pinctrl {	struct regmap			*regmap_base;// Basic register map pointer	int				reg_size;			// Register size	struct regmap			*regmap_pull;// Pull register map pointer	struct regmap			*regmap_pmu;// Power management unit register map pointer	struct device			*dev;		// Device pointer	struct rockchip_pin_ctrl	*ctrl;	// Rockchip chip pin controller pointer	struct pinctrl_desc		pctl;		// Pin controller descriptor	struct pinctrl_dev		*pctl_dev;	// Pin controller device pointer	struct rockchip_pin_group	*groups;// Rockchip chip pin group pointer	unsigned int			ngroups;	// Number of pin groups	struct rockchip_pmx_func	*functions;// Rockchip chip pin function pointer	unsigned int			nfunctions;// Number of pin functions};
    • struct regmap *regmap_base: Pointer to the basic register map (regmap). The basic register map is an interface for accessing chip registers, providing read and write operations on chip registers.

    • int reg_size: Indicates the byte size of the register, used to determine the address range of the register.

    • struct regmap *regmap_pull: Pointer to the pull register map. The pull register map is used to control the pull-up and pull-down functions on the pins.

    • struct regmap *regmap_pmu: Pointer to the power management unit (PMU) register map. The PMU register map is used to control the power management functions of the pins.

    • struct device *dev: Pointer to the device structure. The device structure is used to represent hardware-related devices, including the device’s physical address, interrupts, and other information.

    • struct rockchip_pin_ctrl *ctrl: Pointer to the Rockchip chip pin controller. This structure stores the Rockchip chip-specific pin controller related information and operations.

    • struct pinctrl_desc pctl: Contains an instance of the struct pinctrl_desc structure. It is used to describe the properties and operations of the pin controller, including the pin controller’s name, pin descriptor array, function pointers, etc.

    • struct pinctrl_dev *pctl_dev: Pointer to the pin controller device structure. The pin controller device structure is used to represent the device instance of the pin controller in the system, containing device information and operation interfaces related to the pin controller.

    • struct rockchip_pin_group *groups: Pointer to the Rockchip chip pin group. A pin group is a set of related pins that can be configured and managed together.

    • unsigned int ngroups: Indicates the size of the pin group array, used to determine the length of the pin group array.

    • struct rockchip_pmx_func *functions: Pointer to the Rockchip chip pin function. The pin function defines the different functions that a pin can assume, such as UART, SPI, I2C, etc.

    • unsigned int nfunctions: The number of pin functions. It represents the size of the pin function array, used to determine
      the length of the pin function array.

    struct rockchip_pin_ctrl

    Beforerockchip_pinctrl_probeIn the function, throughctrl = rockchip_pinctrl_get_soc_data(info, pdev)Set

    1234567891011121314151617181920212223242526272829
    struct rockchip_pin_ctrl {	struct rockchip_pin_bank	*pin_banks;// Pointer to the array of pin banks	u32				nr_banks;// Number of pin_banks	u32				nr_pins;// Number of pins	char				*label;// Pin controller label	enum rockchip_pinctrl_type	type;// Pin controller type	int				grf_mux_offset;// Offset of the GRF (Global Register File) mux register	int				pmu_mux_offset;// Offset of the PMU (Power Management Unit) mux register	int				grf_drv_offset;// Offset of the GRF drive register	int				pmu_drv_offset;	struct rockchip_mux_recalced_data *iomux_recalced;	u32				niomux_recalced;	struct rockchip_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 rockchip_pin_bank

    1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859
    /** * struct rockchip_pin_bank * @dev: the pinctrl device bind to the bank * @reg_base: register base of the gpio bank * @regmap_pull: optional separate register for additional pull settings * @clk: clock of the gpio bank * @db_clk: clock of the gpio debounce * @irq: interrupt of the gpio bank * @saved_masks: Saved content of GPIO_INTEN at suspend time. * @pin_base: first pin number * @nr_pins: number of pins in this bank * @name: name of the bank * @bank_num: number of the bank, to account for holes * @iomux: array describing the 4 iomux sources of the bank * @drv: array describing the 4 drive strength sources of the bank * @pull_type: array describing the 4 pull type sources of the bank * @valid: is all necessary information present * @of_node: dt node of this bank * @drvdata: common pinctrl basedata * @domain: irqdomain of the gpio bank * @gpio_chip: gpiolib chip * @grange: gpio range * @slock: spinlock for the gpio bank * @toggle_edge_mode: bit mask to toggle (falling/rising) edge mode * @recalced_mask: bit mask to indicate a need to recalulate the mask * @route_mask: bits describing the routing pins of per bank * @deferred_output: gpio output settings to be done after gpio bank probed * @deferred_lock: mutex for the deferred_output shared btw gpio and pinctrl */struct rockchip_pin_bank {	struct device			*dev;	void __iomem			*reg_base;	struct regmap			*regmap_pull;	struct clk			*clk;	struct clk			*db_clk;	int				irq;	u32				saved_masks;	u32				pin_base;	u8				nr_pins;	char				*name;	u8				bank_num;	struct rockchip_iomux		iomux[4];	struct rockchip_drv		drv[4];	enum rockchip_pin_pull_type	pull_type[4];	bool				valid;	struct device_node		*of_node;	struct rockchip_pinctrl		*drvdata;	struct irq_domain		*domain;	struct gpio_chip		gpio_chip;	struct pinctrl_gpio_range	grange;	raw_spinlock_t			slock;	const struct rockchip_gpio_regs	*gpio_regs;	u32				gpio_type;	u32				toggle_edge_mode;	u32				recalced_mask;	u32				route_mask;	struct list_head		deferred_pins;	struct mutex			deferred_lock;};

    rockchip_pinctrl_probe()

    The probe function in Rockchip’s pinctrl driver function is as follows:

    123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
    static int rockchip_pinctrl_probe(struct platform_device *pdev){	struct rockchip_pinctrl *info; // Pointer to the Rockchip GPIO controller information structure	struct device *dev = &pdev->dev; // Device structure pointer	struct device_node *np = dev->of_node, *node; // Device node pointer	struct rockchip_pin_ctrl *ctrl; // Pointer to the Rockchip GPIO controller configuration structure	struct resource *res;// Device resource pointer	void __iomem *base;// Register base address pointer	int ret;    	// Check whether the device tree node in the device structure exists; if it does not exist, report an error and return an error code.	if (!dev->of_node)		return dev_err_probe(dev, -ENODEV, "device tree node not found\n");	// Use devm_kzalloc function allocates a rockchip_pinctrl structure memory and initialize it to 0	// Allocate and initialize a rockchip_pinctrl structure	info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL);	if (!info)		return -ENOMEM;    	// Assign the device structure pointer to info->dev so that the device structure information can be used in subsequent code.	info->dev = dev;	// Call rockchip_pinctrl_get_soc_data function to obtain the rockchip associated with the device based on device information_pin_ctrl structure.	// If acquisition fails, report an error and return an error code.	ctrl = rockchip_pinctrl_get_soc_data(info, pdev);	if (!ctrl)		return dev_err_probe(dev, -EINVAL, "driver data not available\n");	// Assign the obtained structure pointer to info->ctrl	info->ctrl = ctrl;    	// Use of_parse_phandle function parses the node named "rockchip,grf" in the device tree to obtain the register mapping base address	node = of_parse_phandle(np, "rockchip,grf", 0);	if (node) {        	// If parsing succeeds, call syscon_node_to_The regmap function converts the node to the base address of the register map and stores the result in info->regmap_base		info->regmap_base = syscon_node_to_regmap(node);		of_node_put(node);		if (IS_ERR(info->regmap_base))			return PTR_ERR(info->regmap_base);	} else {// If the "rockchip,grf" node is not found, obtain a resource of type IORESOURCE_MEM to get the register base address		// Through platform_get_resource function obtains a resource of type IORESOURCE_MEM to get the base address of the registers.		// Then use devm_ioremap_resource function maps the resource into memory and stores the result in base.		base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);		if (IS_ERR(base))			return PTR_ERR(base);		// Configure the maximum register address and name of the register mapping		rockchip_regmap_config.max_register = resource_size(res) - 4;		rockchip_regmap_config.name = "rockchip,pinctrl";        	// Use devm_regmap_init_mmio function initializes the register mapping and stores the result in info->regmap_base		info->regmap_base =			devm_regmap_init_mmio(dev, base, &rockchip_regmap_config);		/* to check for the old dt-bindings */		info->reg_size = resource_size(res);// Check old dt-bindings		/* Honor the old binding, with pull registers as 2nd resource */        	// If the controller type is RK3188 and reg_size is less than 0x200, then get the second IORESOURCE_resource of type MEM, as the base address of the pull register		if (ctrl->type == RK3188 && info->reg_size < 0x200) {			base = devm_platform_get_and_ioremap_resource(pdev, 1, &res);			if (IS_ERR(base))				return PTR_ERR(base);			// Configure the maximum register address and name of the pull register mapping			rockchip_regmap_config.max_register = resource_size(res) - 4;			rockchip_regmap_config.name = "rockchip,pinctrl-pull";			info->regmap_pull =				devm_regmap_init_mmio(dev, base, &rockchip_regmap_config);		}	}	/* try to find the optional reference to the pmu syscon */    	// Try to find the optional pmu syscon reference	node = of_parse_phandle(np, "rockchip,pmu", 0);	if (node) {        	// Call syscon_node_to_The regmap function converts the node to the base address of the register map and stores the result in info->regmap_in the PMU		info->regmap_pmu = syscon_node_to_regmap(node);		of_node_put(node);		if (IS_ERR(info->regmap_pmu))			return PTR_ERR(info->regmap_pmu);	}	// Perform special handling for certain SoCs	if (IS_ENABLED(CONFIG_CPU_RK3308) && ctrl->type == RK3308) {		ret = rk3308_soc_data_init(info);		if (ret)			return ret;	}	// Register the rockchip_pinctrl device	ret = rockchip_pinctrl_register(pdev, info);	if (ret)		return ret;	// Set the private data of pdev to info	platform_set_drvdata(pdev, info);	g_pctldev = info->pctl_dev;	// Register the GPIO device	ret = of_platform_populate(np, NULL, NULL, &pdev->dev);	if (ret)		return dev_err_probe(dev, ret, "failed to register gpio device\n");	dev_info(dev, "probed %s\n", dev_name(dev));	return 0;}

    The probe function above initializes and configures the Rockchip GPIO controller, and stores the relevant information instruct rockchip_pinctrl infoand finally registers the related devices and GPIO interfaces.

    • Line 26 callsctrl = rockchip_pinctrl_get_soc_data(info, pdev);Obtain the device-related information based on the device informationrockchip_pin_ctrlstructure.

    • Lines 34 to 70 handle two Device Tree binding methods

      1. New-style binding: reference the system controller (such as GRF) through a phandle;
      2. Old-style binding: directly declare memory resources in the pinctrl node (IORESOURCE_MEM)。

    syscon_node_to_regmap(node)is a mechanism provided by the Linux kernel: converts a syscon node intoregmapinterface.regmapis a generic framework in the kernel for abstracting register read/write, supporting MMIO, I2C, SPI, etc.

    Since the device tree contains:rockchip,grf = <&grf>;therefore the new-style binding is used

    • Line 89 callsret = rockchip_pinctrl_register(pdev, info);registerrockchip_pinctrldevice

    Probe function mind map

    pinctrl
    pinctrl

    rockchip_pinctrl_get_soc_data()

    According to the device tree,compatible = "rockchip,rk3568-pinctrl"Match the pin description data of RK3568, and dynamically calculate the actual offset addresses of the mux (iomux) and drive strength (drv) registers in each GPIO bank, preparing for subsequent pin configuration.

    Under the pinctrl node, eachgpioXnode describes the GPIO controller hardware resources (address, interrupt, clock), but does not include pin mux information — these are controlled by the pinctrl driver throughGRF/PMUGRFregister control.

    RK3568 has a total of 5 GPIO banks (gpio0~gpio4). Each GPIO bank of RK3568 has up to 32 pins, divided into 4 groups (8 pins per group), and each group has its own:

    • iomuxRegister: controls mux function (GPIO / I2C / UART…)
    • drvRegister: controls drive strength (2mA / 4mA / 8mA…)

    etc.

    As in the RK3568 TRM:

    GPIO IOMUX register offset
    GPIO IOMUX register offset

    GPIO drive strength offset
    GPIO drive strength offset

    123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
    /* retrieve the soc specific data */static struct rockchip_pin_ctrl *rockchip_pinctrl_get_soc_data(						struct rockchip_pinctrl *d,						struct platform_device *pdev){	struct device *dev = &pdev->dev;	struct device_node *node = dev->of_node;	const struct of_device_id *match;	struct rockchip_pin_ctrl *ctrl;	struct rockchip_pin_bank *bank;	int grf_offs, pmu_offs, drv_grf_offs, drv_pmu_offs, i, j;    	// Using of_match_node() in rockchip_pinctrl_dt_match table to find the SoC matching the current device node.	match = of_match_node(rockchip_pinctrl_dt_match, node);	ctrl = (struct rockchip_pin_ctrl *)match->data;    	// SoC-specific pin_banks replacement (variant support)	if (IS_ENABLED(CONFIG_CPU_RK3308) && soc_is_rk3308bs())		ctrl->pin_banks = rk3308bs_pin_banks;	if (IS_ENABLED(CONFIG_CPU_PX30) && soc_is_px30s())		ctrl->pin_banks = px30s_pin_banks;    	// Initialize global register offsets	grf_offs = ctrl->grf_mux_offset;	pmu_offs = ctrl->pmu_mux_offset;	drv_pmu_offs = ctrl->pmu_drv_offset;	drv_grf_offs = ctrl->grf_drv_offset;	bank = ctrl->pin_banks;    	// Iterate over all pin banks (RK3568 has 5: gpio0~gpio4)	for (i = 0; i < ctrl->nr_banks; ++i, ++bank) {		int bank_pins = 0;		raw_spin_lock_init(&bank->slock);		bank->drvdata = d;		bank->pin_base = ctrl->nr_pins;		ctrl->nr_pins += bank->nr_pins;		/* calculate iomux and drv offsets */		// Each GPIO bank of RK3568 has up to 32 pins, divided into 4 groups (8 pins per group), and each group has its own:		// iomux register: controls mux function (GPIO / I2C / UART...)		// drv register: controls drive strength (2mA / 4mA / 8mA...)        			for (j = 0; j < 4; j++) { 			struct rockchip_iomux *iom = &bank->iomux[j];			struct rockchip_drv *drv = &bank->drv[j];			int inc;			if (bank_pins >= bank->nr_pins)				break;			/* preset iomux offset value, set new start value */			if (iom->offset >= 0) {				if ((iom->type & IOMUX_SOURCE_PMU) || (iom->type & IOMUX_L_SOURCE_PMU))					pmu_offs = iom->offset;				else					grf_offs = iom->offset;			} else { /* set current iomux offset */				iom->offset = ((iom->type & IOMUX_SOURCE_PMU) ||					       (iom->type & IOMUX_L_SOURCE_PMU)) ?							pmu_offs : grf_offs;			}			/* preset drv offset value, set new start value */			if (drv->offset >= 0) {				if (iom->type & IOMUX_SOURCE_PMU)					drv_pmu_offs = drv->offset;				else					drv_grf_offs = drv->offset;			} else { /* set current drv offset */				drv->offset = (iom->type & IOMUX_SOURCE_PMU) ?						drv_pmu_offs : drv_grf_offs;			}			dev_dbg(dev, "bank %d, iomux %d has iom_offset 0x%x drv_offset 0x%x\n",				i, j, iom->offset, drv->offset);			/*			 * Increase offset according to iomux width.			 * 4bit iomux'es are spread over two registers.			 */			inc = (iom->type & (IOMUX_WIDTH_4BIT |					    IOMUX_WIDTH_3BIT |					    IOMUX_WIDTH_2BIT)) ? 8 : 4;			if ((iom->type & IOMUX_SOURCE_PMU) || (iom->type & IOMUX_L_SOURCE_PMU))				pmu_offs += inc;			else				grf_offs += inc;			/*			 * Increase offset according to drv width.			 * 3bit drive-strenth'es are spread over two registers.			 */			if ((drv->drv_type == DRV_TYPE_IO_1V8_3V0_AUTO) ||			    (drv->drv_type == DRV_TYPE_IO_3V3_ONLY))				inc = 8;			else				inc = 4;			if (iom->type & IOMUX_SOURCE_PMU)				drv_pmu_offs += inc;			else				drv_grf_offs += inc;			bank_pins += 8;		}		/* calculate the per-bank recalced_mask */		for (j = 0; j < ctrl->niomux_recalced; j++) {			int pin = 0;			if (ctrl->iomux_recalced[j].num == bank->bank_num) {				pin = ctrl->iomux_recalced[j].pin;				bank->recalced_mask |= BIT(pin);			}		}		/* calculate the per-bank route_mask */		for (j = 0; j < ctrl->niomux_routes; j++) {			int pin = 0;			if (ctrl->iomux_routes[j].bank_num == bank->bank_num) {				pin = ctrl->iomux_routes[j].pin;				bank->route_mask |= BIT(pin);			}		}	}	return ctrl;}

    Callrockchip_pinctrl_get_soc_data()After:
    Each bank’siomux[j].offsetanddrv[j].offsetare all correctly filled asGRForPMUGRFThe actual register offset in. When the user sets a pin to I2C function through the pinctrl subsystem, the driver will find the corresponding bank and pin group throughregmap_write(info->regmap_base, iomux_offset, value)Write to the GRF register to complete the multiplexing switch.

    syscon

    syscon= abbreviation for “system controller”.

    It is essentially a:

    • Lightweight platform driver (platform driver)
    • Used to convert a segmentMemory-mapped control register area(such as GRF, PMU, CRU, etc.)
    • Encapsulate into a struct regmap Object
    • for other drivers to use through standard interfaces (such asregmap_read/write) safely read and write these registers

    Why is it needed compared to direct ioremap?syscon

    methodproblemSyscon Advantages
    each drives itselfioremapMapping the same physical address multiple times wastes resources.globally unique mapping
    No synchronization mechanismMultiple drivers writing to the same register simultaneously → race conditionregmapBuilt-in lock
    code duplicationEach driver has to handle offsets and bit operations.Unified Abstract Interface
    Strong device tree couplingThe driver needs to know the specific address.Decoupled via phandle.

    struct regmap

    123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
    struct regmap {	union {		struct mutex mutex;		struct {			spinlock_t spinlock;			unsigned long spinlock_flags;		};	};	regmap_lock lock;	regmap_unlock unlock;	void *lock_arg; /* This is passed to lock/unlock functions */	gfp_t alloc_flags;	struct device *dev; /* Device we do I/O on */	void *work_buf;     /* Scratch buffer used to format I/O */	struct regmap_format format;  /* Buffer format */	const struct regmap_bus *bus;	void *bus_context;	const char *name;	bool async;	spinlock_t async_lock;	wait_queue_head_t async_waitq;	struct list_head async_list;	struct list_head async_free;	int async_ret;#ifdef CONFIG_DEBUG_FS	bool debugfs_disable;	struct dentry *debugfs;	const char *debugfs_name;	unsigned int debugfs_reg_len;	unsigned int debugfs_val_len;	unsigned int debugfs_tot_len;	struct list_head debugfs_off_cache;	struct mutex cache_lock;#endif	unsigned int max_register;	bool (*writeable_reg)(struct device *dev, unsigned int reg);	bool (*readable_reg)(struct device *dev, unsigned int reg);	bool (*volatile_reg)(struct device *dev, unsigned int reg);	bool (*precious_reg)(struct device *dev, unsigned int reg);	bool (*writeable_noinc_reg)(struct device *dev, unsigned int reg);	bool (*readable_noinc_reg)(struct device *dev, unsigned int reg);	const struct regmap_access_table *wr_table;	const struct regmap_access_table *rd_table;	const struct regmap_access_table *volatile_table;	const struct regmap_access_table *precious_table;	const struct regmap_access_table *wr_noinc_table;	const struct regmap_access_table *rd_noinc_table;	int (*reg_read)(void *context, unsigned int reg, unsigned int *val);	int (*reg_write)(void *context, unsigned int reg, unsigned int val);	int (*reg_update_bits)(void *context, unsigned int reg,			       unsigned int mask, unsigned int val);	bool defer_caching;	unsigned long read_flag_mask;	unsigned long write_flag_mask;	/* number of bits to (left) shift the reg value when formatting*/	int reg_shift;	int reg_stride;	int reg_stride_order;	/* regcache specific members */	const struct regcache_ops *cache_ops;	enum regcache_type cache_type;	/* number of bytes in reg_defaults_raw */	unsigned int cache_size_raw;	/* number of bytes per word in reg_defaults_raw */	unsigned int cache_word_size;	/* number of entries in reg_defaults */	unsigned int num_reg_defaults;	/* number of entries in reg_defaults_raw */	unsigned int num_reg_defaults_raw;	/* if set, only the cache is modified not the HW */	bool cache_only;	/* if set, only the HW is modified not the cache */	bool cache_bypass;	/* if set, remember to free reg_defaults_raw */	bool cache_free;	struct reg_default *reg_defaults;	const void *reg_defaults_raw;	void *cache;	/* if set, the cache contains newer data than the HW */	bool cache_dirty;	/* if set, the HW registers are known to match map->reg_defaults */	bool no_sync_defaults;	struct reg_sequence *patch;	int patch_regs;	/* if set, converts bulk read to single read */	bool use_single_read;	/* if set, converts bulk write to single write */	bool use_single_write;	/* if set, the device supports multi write mode */	bool can_multi_write;	/* if set, raw reads/writes are limited to this size */	size_t max_raw_read;	size_t max_raw_write;	struct rb_root range_tree;	void *selector_work_buf;	/* Scratch buffer used for selector */	struct hwspinlock *hwlock;	/* if set, the regmap core can sleep */	bool can_sleep;};

    Common system controllers in Rockchip SoCs include:

    controllerFull nameFunction
    GRFGeneral Register FilesControls GPIO multiplexing, voltage domains, peripheral routing, etc.
    PMUPower Management UnitLow-power pin control, power management.

    These registers usually:

    • are shared by multiple subsystems(e.g., pinctrl, USB, I2C all need to configure GRF)
    • Cannot be exclusively owned by a single driver.
    • Need Atomic operations, bit operations, lock protection.

    sysconExactly solve these problems.

    syscon device tree

    123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
    pmugrf: syscon@fdc20000 {	compatible = "rockchip,rk3568-pmugrf", "syscon", "simple-mfd";	reg = <0x0 0xfdc20000 0x0 0x10000>;	pmu_io_domains: io-domains {		compatible = "rockchip,rk3568-pmu-io-voltage-domain";		status = "disabled";	};	reboot_mode: reboot-mode {		compatible = "syscon-reboot-mode";		offset = <0x200>;		mode-bootloader = <BOOT_BL_DOWNLOAD>;		mode-charge = <BOOT_CHARGING>;		mode-fastboot = <BOOT_FASTBOOT>;		mode-loader = <BOOT_BL_DOWNLOAD>;		mode-normal = <BOOT_NORMAL>;		mode-recovery = <BOOT_RECOVERY>;		mode-ums = <BOOT_UMS>;		mode-panic = <BOOT_PANIC>;		mode-watchdog = <BOOT_WATCHDOG>;	};};pipegrf: syscon@fdc50000 {	compatible = "rockchip,rk3568-pipegrf", "syscon";	reg = <0x0 0xfdc50000 0x0 0x1000>;};grf: syscon@fdc60000 {	compatible = "rockchip,rk3568-grf", "syscon", "simple-mfd";	reg = <0x0 0xfdc60000 0x0 0x10000>;	io_domains: io-domains {		compatible = "rockchip,rk3568-io-voltage-domain";		status = "disabled";	};	lvds0: lvds: lvds {		compatible = "rockchip,rk3568-lvds";		phys = <&video_phy0>;		phy-names = "phy";		status = "disabled";		ports {			#address-cells = <1>;			#size-cells = <0>;			port@0 {				reg = <0>;				#address-cells = <1>;				#size-cells = <0>;				lvds0_in_vp1: lvds_in_vp1: endpoint@1 {					reg = <1>;					remote-endpoint = <&vp1_out_lvds>;					status = "disabled";				};				lvds0_in_vp2: lvds_in_vp2: endpoint@2 {					reg = <2>;					remote-endpoint = <&vp2_out_lvds>;					status = "disabled";				};			};		};	};	lvds1: lvds1 {		compatible = "rockchip,rk3568-lvds";		phys = <&video_phy1>;		phy-names = "phy";		status = "disabled";		ports {			#address-cells = <1>;			#size-cells = <0>;			port@0 {				reg = <0>;				#address-cells = <1>;				#size-cells = <0>;				lvds1_in_vp1: endpoint@0 {					reg = <0>;					remote-endpoint = <&vp1_out_lvds1>;				};				lvds1_in_vp2: endpoint@1 {					reg = <1>;					remote-endpoint = <&vp2_out_lvds1>;				};			};		};	};	rgb: rgb {		compatible = "rockchip,rk3568-rgb";		pinctrl-names = "default";		pinctrl-0 = <&lcdc_ctl>;		status = "disabled";		ports {			#address-cells = <1>;			#size-cells = <0>;			port@0 {				reg = <0>;				#address-cells = <1>;				#size-cells = <0>;				rgb_in_vp2: endpoint@2 {					reg = <2>;					remote-endpoint = <&vp2_out_rgb>;					status = "disabled";				};			};		};	};};
    • GRFGeneral Register Files — main system controller,core dependency of pinctrl
    • Almost all peripheral multiplexing, enabling, and voltage domains are configured here.
    • Sub-functions:
      • io_domains: main IO voltage domain control (e.g., levels for HDMI, MIPI, SDIO)
      • lvds0 / lvds1: LVDS display output controller (connects to screen)
      • rgb: RGB parallel display interface (legacy LCD)

    Key points:

    • must include"syscon"Beforecompatiblein the list
    • in the kernelsysconthe driver will match all that have"syscon"the node
    • automatically createdregmapand cache it for other drivers to use viaof_xlateorsyscon_node_to_regmap()Get

    Kernel API usage example

    1. Get the syscon regmap

    123
    struct device_node *np = of_parse_phandle(dev->of_node, "rockchip,grf", 0);struct regmap *grf_regmap = syscon_node_to_regmap(np);// Subsequently, you can call regmap_write(grf_regmap, offset, value);

    2. Get directly via phandle

    1
    struct regmap *grf = syscon_regmap_lookup_by_phandle(dev->of_node, "rockchip,grf");

    3. Global lookup

    1
    struct regmap *grf = syscon_regmap_lookup_by_compatible("rockchip,rk3399-grf");

    rockchip_pinctrl_register()

    rockchip_pinctrl_probe()The function finally callsrockchip_pinctrl_register()function registrationrockchip_pinctrldevice

    1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253
    static int rockchip_pinctrl_register(struct platform_device *pdev,					struct rockchip_pinctrl *info){ 	// info's pctl is pinctrl_desc	struct pinctrl_desc *ctrldesc = &info->pctl;	struct pinctrl_pin_desc *pindesc, *pdesc;	struct rockchip_pin_bank *pin_bank;	struct device *dev = &pdev->dev;	int pin, bank, ret;	int k;    	// Initialize the pinctrl descriptor structure pinctrl_desc	ctrldesc->name = "rockchip-pinctrl";	ctrldesc->owner = THIS_MODULE;	ctrldesc->pctlops = &rockchip_pctrl_ops;  // pinctrl control operation function	ctrldesc->pmxops = &rockchip_pmx_ops;	  // pinctrl pin mux operation function	ctrldesc->confops = &rockchip_pinconf_ops;// pinctrl pin configuration operation function    	// Use the devm_kcalloc function to allocate a contiguous memory area in the device's memory for storing the pin descriptor structure.	pindesc = devm_kcalloc(dev, info->ctrl->nr_pins, sizeof(*pindesc), GFP_KERNEL);	if (!pindesc)		return -ENOMEM;	ctrldesc->pins = pindesc;//By assigning the pin descriptor structure pointer pindesc to the pins member of the pinctrl descriptor structure	ctrldesc->npins = info->ctrl->nr_pins;//Assign the pin count info->ctrl->nr_pins to the npins member of the pinctrl descriptor structure.	pdesc = pindesc;// Define a variable pdesc pointing to the starting address of the pin descriptor structure.    	// Traverse the bank to which each pin belongs, and set the number and name for each pin.	for (bank = 0, k = 0; bank < info->ctrl->nr_banks; bank++) {        	// The outer loop traverses the bank to which each pin belongs.		pin_bank = &info->ctrl->pin_banks[bank];		for (pin = 0; pin < pin_bank->nr_pins; pin++, k++) {//pin is the index of the current pin in the bank.            		// The inner loop traverses the pins in each bank.			pdesc->number = k;//The current pin's number k			pdesc->name = kasprintf(GFP_KERNEL, "%s-%d",						pin_bank->name, pin);			pdesc++;		}		INIT_LIST_HEAD(&pin_bank->deferred_pins);		mutex_init(&pin_bank->deferred_lock);	}	// Parse the pinctrl information in the device tree. This function sets the default configuration of pins according to the description in the device tree.	ret = rockchip_pinctrl_parse_dt(pdev, info);	if (ret)		return ret;	// Register the pinctrl device. It takes the pinctrl description structure, pinctrl-related operation functions, and private data as parameters to register the pinctrl device into the system.	info->pctl_dev = devm_pinctrl_register(dev, ctrldesc, info);	if (IS_ERR(info->pctl_dev))		return dev_err_probe(dev, PTR_ERR(info->pctl_dev), "could not register pinctrl driver\n");	return 0;}
    • Lines 29 to 42 traverse the bank to which each pin belongs in a double for loop, setting the number and name for the pins of each bank.
    • Line 44ret = rockchip_pinctrl_parse_dt(pdev, info);Parse the pinctrl information in the device tree. This function sets the default configuration of pins according to the description in the device tree.
    • Line 48info->pctl_dev = devm_pinctrl_register(dev, ctrldesc, info);willpdev->devinfo->pctlandinfoPass in and register the pinctrl device. The pinctrl description structure, pinctrl-related operation functions, and private data are used as parameters to register the pinctrl device into the system.

    rockchip_pinctrl_parse_dt()

    rockchip_pinctrl_register()Called in the function.rockchip_pinctrl_parse_dt()Parse the pinctrl information in the device tree.

    123456789101112131415161718192021222324252627282930313233343536373839404142
    static int rockchip_pinctrl_parse_dt(struct platform_device *pdev,					      struct rockchip_pinctrl *info){	struct device *dev = &pdev->dev;	struct device_node *np = dev->of_node;	struct device_node *child;	int ret;	int i;	// Count the number of child nodes and update the counter in the info structure.	rockchip_pinctrl_child_count(info, np);	dev_dbg(dev, "nfunctions = %d\n", info->nfunctions);	dev_dbg(dev, "ngroups = %d\n", info->ngroups);	// Allocate memory space for functions and groups.	info->functions = devm_kcalloc(dev, info->nfunctions, sizeof(*info->functions), GFP_KERNEL);	if (!info->functions)		return -ENOMEM;	info->groups = devm_kcalloc(dev, info->ngroups, sizeof(*info->groups), GFP_KERNEL);	if (!info->groups)		return -ENOMEM;	i = 0;	// Traverse each child node and parse the function information.	for_each_child_of_node(np, child) {        	// If the node is not a function node, continue to the next node.		if (of_match_node(rockchip_bank_match, child))			continue;		// Parse the function information and store it in the info structure.		ret = rockchip_pinctrl_parse_functions(child, info, i++);		if (ret) {			dev_err(dev, "failed to parse function\n");			of_node_put(child);			return ret;		}	}	return 0;}
    • Called on line 10.rockchip_pinctrl_child_count(info, np);Count the number of child nodes and update the counter in the info structure.
    • Lines 25 to 36, byfor_each_child_of_node(np, child)Traverse each child node and call.ret = rockchip_pinctrl_parse_functions(child, info, i++);Parse function information.

    rockchip_pinctrl_child_count()

    rockchip_pinctrl_parse_dt()In the function, by calling.rockchip_pinctrl_child_count(info, np);Count the number of child nodes and update the counter in the info structure.

    1234567891011121314151617
    static void rockchip_pinctrl_child_count(struct rockchip_pinctrl *info,						struct device_node *np){	struct device_node *child;	// Traverse the child nodes of the device node.	for_each_child_of_node(np, child) {        	// If the child node is not a function node, skip the current node and continue traversing the next node.		if (of_match_node(rockchip_bank_match, child))			continue;		// If the child node is a function node, increment the function counter.		info->nfunctions++;        	// Get the number of child nodes of the child node and add it to the group counter.		info->ngroups += of_get_child_count(child);	}}

    rockchip_pinctrl_parse_functions()

    rockchip_pinctrl_parse_dt()In the function, by calling.rockchip_pinctrl_parse_functions()Parse the function information and store it in the info structure.

    1234567891011121314151617181920212223242526272829303132333435363738394041424344454647
    static int rockchip_pinctrl_parse_functions(struct device_node *np,						struct rockchip_pinctrl *info,						u32 index){	struct device *dev = info->dev;	struct device_node *child;	struct rockchip_pmx_func *func;// Used to store function information.	struct rockchip_pin_group *grp;// Used to store groups information.	int ret;	static u32 grp_index;	u32 i = 0;	// Print debug information, showing the function node and index currently being parsed.	dev_dbg(dev, "parse function(%d): %pOFn\n", index, np);    	// Get the pointer to the current function in the info->functions array.	func = &info->functions[index];	/* Initialise function */    	/* Initialize the function. */	func->name = np->name;    	// Get the number of child nodes of the function node, i.e., the number of associated groups.	func->ngroups = of_get_child_count(np);	if (func->ngroups <= 0)		return 0;    	// Allocate memory space for the function's group pointer array.	func->groups = devm_kcalloc(dev, func->ngroups, sizeof(*func->groups), GFP_KERNEL);	if (!func->groups)		return -ENOMEM;    	// Iterate over each child node of the function node.	for_each_child_of_node(np, child) {        	// Store the child node's name into the function's group pointer array.		func->groups[i] = child->name;        	// Get the corresponding group pointer from the info->groups array.		grp = &info->groups[grp_index++];        	// Parse group information and store the result into the corresponding group pointer.		ret = rockchip_pinctrl_parse_groups(child, grp, info, i++);		if (ret) {			of_node_put(child);			return ret;		}	}	return 0;}

    rockchip_pinctrl_parse_functionsin:

    • func = &info->functions[index], sostruct rockchip_pinctrloffunctionsThe purpose of the parameter is to storepinctrlin the device treefunctioninformation.
    • grp = &info->groups[grp_index++];, sostruct rockchip_pinctrlofgroupsThe purpose of the parameter is to storepinctrlin the device treegroupsinformation.
    rockchip_pinctrl_parse_groups()

    rockchip_pinctrl_parse_functionsthroughret = rockchip_pinctrl_parse_groups(child, grp, info, i++);Parse group information and store the result into the corresponding group pointer.

    1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071
    static int rockchip_pinctrl_parse_groups(struct device_node *np,					      struct rockchip_pin_group *grp,					      struct rockchip_pinctrl *info,					      u32 index){	struct device *dev = info->dev;	struct rockchip_pin_bank *bank;	int size;	const __be32 *list;	int num;	int i, j;	int ret;	// Print debug information, showing the group node and index currently being parsed.	dev_dbg(dev, "group(%d): %pOFn\n", index, np);	/* Initialise group */    	// Initialize group information, set the pin group name to the node name.	grp->name = np->name;	/*	 * the binding format is rockchip,pins = <bank pin mux CONFIG>,	 * do sanity check and calculate pins number	 */    		/*	* The binding format is rockchip,pins = <bank pin mux CONFIG>,	* Perform validity check and calculate the number of pins	*/	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)//If the property value is empty or the count is not a multiple of 4		return dev_err_probe(dev, -EINVAL, "wrong pins number or pins and configs should be by 4\n");	grp->npins = size / 4;// Calculate the number of pins in the group	// Based on the calculated number of pins, allocate memory space for the pin array and data array, which will be used to store pin numbers and related configuration information	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;	// Iterate over each element in the list; every 4 elements represent information for one pin	for (i = 0, j = 0; i < size; i += 4, j++) {		const __be32 *phandle;		struct device_node *np_config;		// Get the pin number		num = be32_to_cpu(*list++);        	// Convert the pin number to the corresponding pin structure pointer		bank = bank_num_to_bank(info, num);		if (IS_ERR(bank))			return PTR_ERR(bank);		// Calculate the pin number based on the pin base address (pin_base) in the pin structure and the value in the list, and store it in the pin array (grp->pins)		grp->pins[j] = bank->pin_base + be32_to_cpu(*list++);        	// Get the function selection value associated with the current pin from the list, and store it in the corresponding position in the data array (grp->data)		grp->data[j].func = be32_to_cpu(*list++);        	// Get configuration information related to the pin		phandle = list++;		if (!phandle)			return -EINVAL;		// Get the handle of the configuration information associated with the current pin from the list, and use this handle to find the corresponding configuration node (np_config)		np_config = of_find_node_by_phandle(be32_to_cpup(phandle));        	// Parse the configuration information and store the result in the group's data array		ret = pinconf_generic_parse_dt_config(np_config, NULL,				&grp->data[j].configs, &grp->data[j].nconfigs);		if (ret)			return ret;	}	return 0;}

    devm_pinctrl_register()

    rockchip_pinctrl_register()The function usesinfo->pctl_dev = devm_pinctrl_register(dev, ctrldesc, info);Register the pinctrl device. One parameter type isstruct device *, the second parameter type is struct pinctrl_desc *, the third parameter type isvoid *is the private data of the pin controller.

    1. struct device *dev = &pdev->dev;
    2. struct pinctrl_desc *ctrldesc = &info->pctl
    3. struct rockchip_pinctrl *info
    1234567891011121314151617181920212223242526272829303132333435
    // drivers/pinctrl/core.c/** * devm_pinctrl_register() - Resource managed version of pinctrl_register(). * @dev: parent device for this pin controller * @pctldesc: descriptor for this pin controller * @driver_data: private pin controller data for this pin controller * * Returns an error pointer if pincontrol register failed. Otherwise * it returns valid pinctrl handle. * * The pinctrl device will be automatically released when the device is unbound. */struct pinctrl_dev *devm_pinctrl_register(struct device *dev,					  struct pinctrl_desc *pctldesc,					  void *driver_data){	struct pinctrl_dev **ptr, *pctldev;	// Use devres_alloc function for storing pinctrl_allocate memory for the variable ptr that holds the dev pointer	ptr = devres_alloc(devm_pinctrl_dev_release, sizeof(*ptr), GFP_KERNEL);	if (!ptr)		return ERR_PTR(-ENOMEM);	// Call pinctrl_register function registers the pinctrl device. This function takes pinctrl_desc structure, device pointer dev, and driver data driver_data as parameters, and returns the registered pinctrl_dev pointer	pctldev = pinctrl_register(pctldesc, dev, driver_data);	if (IS_ERR(pctldev)) {		devres_free(ptr);		return pctldev;	}	// Store the pinctrl_dev pointer to the memory location pointed to by ptr.	*ptr = pctldev;    	// Use the devres_add function to add ptr to the device's resource list. In this way, when the device is released, the previously allocated memory will be automatically freed.	devres_add(dev, ptr);	return pctldev;}EXPORT_SYMBOL_GPL(devm_pinctrl_register);

    devres_allocThe function is used to manage device resources, and it allocates memory in the device’s resource list. The size of memory allocated here issizeof(*ptr)bytes, i.e., apinctrl_devpointer size. If memory allocation fails, return-ENOMEM

    pinctrl_register()

    devm_pinctrl_register()by callingpctldev = pinctrl_register(pctldesc, dev, driver_data);register the pinctrl device. This function takesstruct pinctrl_desc *pctldesc, device pointerstruct device *devand driver datavoid *driver_dataas parameters, and returns the registeredstruct pinctrl_dev*pointer

    1234567891011121314151617181920212223242526272829
    // 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){	struct pinctrl_dev *pctldev;	int error;	// Initialize the pinctrl controller	pctldev = pinctrl_init_controller(pctldesc, dev, driver_data);	if (IS_ERR(pctldev))		return pctldev;	// Enable the pinctrl controller	error = pinctrl_enable(pctldev);	if (error)		return ERR_PTR(error);	return pctldev;}EXPORT_SYMBOL_GPL(pinctrl_register);

    pinctrl_init_controller()

    pinctrl_register()throughpctldev = pinctrl_init_controller(pctldesc, dev, driver_data);Initialize the pinctrl controller

    123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
    /** * pinctrl_init_controller() - init 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 */static struct pinctrl_dev *pinctrl_init_controller(struct pinctrl_desc *pctldesc, struct device *dev,			void *driver_data){	struct pinctrl_dev *pctldev;	int ret;	if (!pctldesc)		return ERR_PTR(-EINVAL);	if (!pctldesc->name)		return ERR_PTR(-EINVAL);	pctldev = kzalloc(sizeof(*pctldev), GFP_KERNEL);	if (!pctldev)		return ERR_PTR(-ENOMEM);	/* Initialize pin control device struct */    	/* Initialize the pin control device structure */	pctldev->owner = pctldesc->owner;// Set owner	pctldev->desc = pctldesc;// Set descriptor	pctldev->driver_data = driver_data; // Set driver data	INIT_RADIX_TREE(&pctldev->pin_desc_tree, GFP_KERNEL);// Initialize the pin descriptor tree#ifdef CONFIG_GENERIC_PINCTRL_GROUPS	INIT_RADIX_TREE(&pctldev->pin_group_tree, GFP_KERNEL);// Initialize the pin group tree#endif#ifdef CONFIG_GENERIC_PINMUX_FUNCTIONS	INIT_RADIX_TREE(&pctldev->pin_function_tree, GFP_KERNEL);// Initialize the pin function tree#endif	INIT_LIST_HEAD(&pctldev->gpio_ranges);// Initialize the GPIO range linked list	INIT_LIST_HEAD(&pctldev->node);// Initialize the node linked list	pctldev->dev = dev;// Set device pointer	mutex_init(&pctldev->mutex);// Initialize the mutex lock	/* check core ops for sanity */    	/* Check the validity of core operation functions */	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 pin multiplexing is implemented, check the validity of the operation function. */	if (pctldesc->pmxops) {		ret = pinmux_check_ops(pctldev);		if (ret)			goto out_err;	}	/* If we're implementing pinconfig, check the ops for sanity */    	/* If the pin configuration function is implemented, check the validity of the operation function. */	if (pctldesc->confops) {		ret = pinconf_check_ops(pctldev);		if (ret)			goto out_err;	}	/* Register all the pins */    	/* Register all 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;	}	return pctldev;out_err:	mutex_destroy(&pctldev->mutex);	kfree(pctldev);	return ERR_PTR(ret);}

    In this function, what we need to focus on is the content of line 27.pctldev->driver_data = driver_data, where the rvaluedriver_dataIt is passed step by step from the probe function of pinctrl, and is astruct rockchip_pinctrl *a structure pointer variable of type, lvaluepctldevFor the pin controller device to be registered, at this point the two data structures have established a connection, and can throughpctldevcome to the right placerockchip_pinctrlaccess the data in.

    pinctrl subsystem function operation set

    123
    const struct pinctrl_ops *pctlops; // Pin control operation function pointerconst struct pinmux_ops *pmxops;   // Pin multiplexing operation function pointerconst struct pinconf_ops *confops; // Pin configuration operation function pointer

    pinctrl_ops

    1234567891011121314151617181920212223242526272829303132333435
    /** * 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);//Get the number of pin groups supported by the specified Pin Control device.	const char *(*get_group_name) (struct pinctrl_dev *pctldev,				       unsigned selector);// Get the pin group name corresponding to the specified pin group selector.	int (*get_group_pins) (struct pinctrl_dev *pctldev,			       unsigned selector,			       const unsigned **pins,			       unsigned *num_pins);// Get the list of pins in the pin group corresponding to the specified pin group selector.	void (*pin_dbg_show) (struct pinctrl_dev *pctldev, struct seq_file *s,			  unsigned offset);//Output the pin information corresponding to the specified pin selector in the debug information.	int (*dt_node_to_map) (struct pinctrl_dev *pctldev,			       struct device_node *np_config,			       struct pinctrl_map **map, unsigned *num_maps);// Create the Pin Control mapping associated with the given device tree node.	void (*dt_free_map) (struct pinctrl_dev *pctldev,			     struct pinctrl_map *map, unsigned num_maps);//Release before passing dt_node_Pin Control mapping created by to_map};

    Specific implementation:

    1234567
    static const struct pinctrl_ops rockchip_pctrl_ops = {	.get_groups_count	= rockchip_get_groups_count,	.get_group_name		= rockchip_get_group_name,	.get_group_pins		= rockchip_get_group_pins,	.dt_node_to_map		= rockchip_dt_node_to_map,	.dt_free_map		= rockchip_dt_free_map,};

    get_groups_count

    Get the number of pin groups.

    1234567
    static int rockchip_get_groups_count(struct pinctrl_dev *pctldev){    	// From pinctrl_Get the private data pointer in the dev structure and convert it to rockchip._pinctrl structure	struct rockchip_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);	// Return the number of pin groups stored in the rockchip_pinctrl structure.	return info->ngroups;}

    get_group_name

    Get the name of the pin group.

    123456789
    static const char *rockchip_get_group_name(struct pinctrl_dev *pctldev,							unsigned selector){    	// From pinctrl_Get the private data pointer in the dev structure and convert it to rockchip._pinctrl structure	struct rockchip_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);    	// Return the name of the specified pin group.	return info->groups[selector].name;}

    get_group_pins

    Get the pin list of the pin group.

    123456789101112131415161718
    static int rockchip_get_group_pins(struct pinctrl_dev *pctldev,				      unsigned selector, const unsigned **pins,				      unsigned *npins){    	// From pinctrl_Get the private data pointer in the dev structure and convert it to rockchip._pinctrl structure	struct rockchip_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);    	// If the selector exceeds the range of pin groups, return the error code -EINVAL.	if (selector >= info->ngroups)		return -EINVAL;    	// Assign the pointer to the pin array of the pin group to the passed-in pins pointer.	*pins = info->groups[selector].pins;    	// Assign the number of pins in the pin group to the passed-in npins variable.	*npins = info->groups[selector].npins;	return 0;}

    dt_node_to_map

    Create the Pin Control mapping associated with the device tree node. That is, a “pin configuration node” in the device tree (such asi2c1_xfer: i2c1-xfer {...})into what the kernel pinctrl system can understandstruct pinctrl_mapmapping table, thereby telling the system: “When a certain device is used, configure which pins to what function + electrical parameters.”

    For example:

    12345678910111213
    &pinctrl {	i2c1_xfer: i2c1-xfer {		rockchip,pins =			<1 RK_PB0 1 &pcfg_pull_up>,   // GPIO1_B0 → I2C1_SCL			<1 RK_PB1 1 &pcfg_pull_up>;   // GPIO1_B1 → I2C1_SDA	};};&i2c1 {	pinctrl-names = "default";	pinctrl-0 = <&i2c1_xfer>;	status = "okay";};
    • Defines a pin configuration blocki2c1_xfer
    • When the I2C1 controller is working, it needs:
      • hold GPIO1_B0 Configure as I2C1_SCL function (mux value = 1), and enable pull-up
      • hold GPIO1_B1 Configure as I2C1_SDA function (mux value = 1), and enable pull-up

    The pinctrl driver relies ondt_node_to_map()to translate this DTS node into kernel structures

    struct pinctrl_map
    1234567891011121314151617181920212223242526
    // 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 */struct pinctrl_map {	const char *dev_name;// device name	const char *name;// mapping name	enum pinctrl_map_type type;// mapping type	const char *ctrl_dev_name;// control device name	union {		struct pinctrl_map_mux mux;// pinmux mapping data		struct pinctrl_map_configs configs; // configuration mapping data	} data;};
    fieldmeaningDescription
    dev_namedevice name using this pin configurationusually the name of the peripheral, such as"fe8a0000.i2c". If set to the pinctrl controller’s own name (such as"pinctrl"), it is called a hogged pin (occupied at startup, independent of peripherals).
    namethe state name of this mappingcorresponds to the device tree’spinctrl-names = "xxx", for example"default""sleep". When callingpinctrl_lookup_state(pctl, "default")it will be used.
    typemapping typeenum value, common ones:
    PIN_MAP_TYPE_MUX_GROUP: configure pin muxing
    PIN_MAP_TYPE_CONFIGS_PIN: configure electrical parameters of a single pin
    PIN_MAP_TYPE_CONFIGS_GROUP: configure electrical parameters of the entire pin group
    ctrl_dev_namethe name of the pinctrl device that controls this pinUsually,"pinctrl"or"rockchip-pinctrl", used to find the corresponding pinctrl driver.
    dataSpecific configuration content (union)According totypedifferent, use.muxor.configs
    struct pinctrl_map_mux
    1234567891011
    /** * struct pinctrl_map_mux - mapping table content for MAP_TYPE_MUX_GROUP * @group: the name of the group whose mux function is to be configured. This *	field may be left NULL, and the first applicable group for the function *	will be used. * @function: the mux function to select for the group */struct pinctrl_map_mux {	const char *group;	const char *function;};
    fieldmeaning
    groupPin group name, e.g."i2c1-xfer""uart2-m1". This group is predefined in the pinctrl driver and contains a set of physical pins.
    functionThe function name to switch to, e.g."i2c1""uart2". The pinctrl driver internally knows how to map this function to specific register values.
    struct pinctrl_map_configs

    Electrical parameter configuration mapping, used to set the pin’s Electrical characteristics, such as pull-up/pull-down, drive strength, Schmitt trigger, etc.

    1234567891011121314
    /** * struct pinctrl_map_configs - mapping table content for MAP_TYPE_CONFIGS_* * @group_or_pin: the name of the pin or group whose configuration parameters *	are to be configured. * @configs: a pointer to an array of config parameters/values to program into *	hardware. Each individual pin controller defines the format and meaning *	of config parameters. * @num_configs: the number of entries in array @configs */struct pinctrl_map_configs {	const char *group_or_pin;	unsigned long *configs;	unsigned num_configs;};
    fieldmeaning
    group_or_pinThe object to configure can be a pin name (e.g."gpio1-16") or a pin group name (e.g."i2c1-xfer")。
    configsConfiguration parameter array, each element is aunsigned long, encoding the configuration item and value (e.g.PIN_CONFIG_BIAS_PULL_UP)。
    num_configsConfiguration item count, arrayconfigslength.

    Example:

    123456789101112
    unsigned long i2c_pull_up[] = {    PIN_CONFIG_BIAS_PULL_UP,   // Parameter type};{  .type = PIN_MAP_TYPE_CONFIGS_PIN,  .data.configs = {    .group_or_pin = "gpio1-16",    .configs = i2c_pull_up,    .num_configs = 1  }}

    Meaning: for the pingpio1-16enable pull-up resistor

    rockchip_dt_node_to_map()

    12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667
    static int rockchip_dt_node_to_map(struct pinctrl_dev *pctldev,				 struct device_node *np,				 struct pinctrl_map **map, unsigned *num_maps){    	// Get the pin controller's private data pointer	struct rockchip_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);    	// Pin group pointer	const struct rockchip_pin_group *grp;    	// Device pointer	struct device *dev = info->dev;    	// New pin mapping array	struct pinctrl_map *new_map;    	// Parent node pointer	struct device_node *parent;    	// Mapping count, default is 1	int map_num = 1;	int i;	/*	 * first find the group of this node and check if we need to create	 * config maps for pins	 */    	/* Find pin group */	grp = pinctrl_name_to_group(info, np->name);// Find the corresponding pin group according to the node name	if (!grp) {// If the pin group is not found, print an error message.		dev_err(dev, "unable to find group for node %pOFn\n", np);		return -EINVAL;	}	map_num += grp->npins;// Calculate the number of mappings, including mux mappings and config mappings.	new_map = kcalloc(map_num, sizeof(*new_map), GFP_KERNEL);// Allocate memory space for storing the mapping array.	if (!new_map)		return -ENOMEM;	*map = new_map;// Assign the allocated mapping array to the output parameter.	*num_maps = map_num;// Assign the mapping count to the output parameter.	/* create mux map */    	/* Create mux mappings. */	parent = of_get_parent(np); // Get the parent node of the node.	if (!parent) {		kfree(new_map);// If the parent node does not exist, free the allocated memory space of the mapping array.		return -EINVAL;	}	new_map[0].type = PIN_MAP_TYPE_MUX_GROUP;// Set the mapping type to mux mapping.	new_map[0].data.mux.function = parent->name;// The mux function name is the name of the parent node.	new_map[0].data.mux.group = np->name; // Use the device node's name as the group name of the mapping.	of_node_put(parent);// Release the reference count of the parent node.	/* create config map */    	/* Create config mappings. */	new_map++;// Move the mapping array pointer forward by one position.	for (i = 0; i < grp->npins; i++) {		new_map[i].type = PIN_MAP_TYPE_CONFIGS_PIN;// Set the mapping type to config mapping.		new_map[i].data.configs.group_or_pin =				pin_get_name(pctldev, grp->pins[i]);// The pin group or pin name is the pin name in the pin group.		new_map[i].data.configs.configs = grp->data[i].configs;// The configuration array is the configuration information for the pin in the pin group.		new_map[i].data.configs.num_configs = grp->data[i].nconfigs;// The configuration count is the number of configurations for the pin in the pin group.	}	// Print debug information showing the function name, group name, and count of the created pin mappings.	dev_dbg(dev, "maps: function %s group %s num %d\n",		(*map)->data.mux.function, (*map)->data.mux.group, map_num);	return 0;}

    rockchip_dt_node_to_mapThe function creates pin mappings based on the device node information, including mux mappings and config mappings.

    • Mux mappings are used to associate the function of the pin group with the function of the parent node.
    • Config mappings are used to associate the pin’s configuration information with the pin’s name.

    These mappings will be used to configure the pin controller to ensure that the pins are correctly configured and used in the system. This function is called during device tree parsing to create the corresponding pin mappings for each device node.

    dt_free_map

    Release thedt_node_to_mapPin Control mappings created.

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

    pinconf_ops

    struct pinconf_opsIt is the core operation interface in the pinctrl subsystem for pin electrical characteristic configuration (pin configuration).

    If we saypinmux_opsis responsible for ‘which functional module the pin is connected to’ (such as I2C, UART), thenpinconf_opsis responsible for ‘how to set the electrical behavior of this pin’ (such as pull-up resistor, drive strength, Schmitt trigger, etc.).

    1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556
    /** * 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 */struct pinconf_ops {#ifdef CONFIG_GENERIC_PINCONF	bool is_generic;// Whether it is a generic pin configuration operation#endif     	// Get pin configuration information	int (*pin_config_get) (struct pinctrl_dev *pctldev,			       unsigned pin,			       unsigned long *config);    	// Set pin configuration information	int (*pin_config_set) (struct pinctrl_dev *pctldev,			       unsigned pin,			       unsigned long *configs,			       unsigned num_configs);    	// Get pin group configuration information	int (*pin_config_group_get) (struct pinctrl_dev *pctldev,				     unsigned selector,				     unsigned long *config);    	// Set pin group configuration information	int (*pin_config_group_set) (struct pinctrl_dev *pctldev,				     unsigned selector,				     unsigned long *configs,				     unsigned num_configs);    	// Debug function, display pin configuration information	void (*pin_config_dbg_show) (struct pinctrl_dev *pctldev,				     struct seq_file *s,				     unsigned offset);     	// Debug function, display pin group configuration information	void (*pin_config_group_dbg_show) (struct pinctrl_dev *pctldev,					   struct seq_file *s,					   unsigned selector);    	// Debug function, display specific pin configuration information	void (*pin_config_config_dbg_show) (struct pinctrl_dev *pctldev,					    struct seq_file *s,					    unsigned long config);};

    Structstruct pinconf_ops, used forDefine pin configuration operationsfunction pointers. Each function pointer corresponds to a specific operation, such as getting pin configuration, setting pin configuration, getting pin group configuration, etc. These functions are implemented in the driver to configure and control hardware pins.

    12345
    static const struct pinconf_ops rockchip_pinconf_ops = {	.pin_config_get			= rockchip_pinconf_get,// Function to get pin configuration	.pin_config_set			= rockchip_pinconf_set,// Function to set pin configuration	.is_generic			= true,};

    pin_config_get

    Get pin configuration information.

    1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
    /* get the pin config settings for a specified pin */static int rockchip_pinconf_get(struct pinctrl_dev *pctldev, unsigned int pin,							unsigned long *config){	struct rockchip_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);	struct rockchip_pin_bank *bank = pin_to_bank(info, pin);	struct gpio_chip *gpio = &bank->gpio_chip;	enum pin_config_param param = pinconf_to_config_param(*config);	u16 arg;	int rc;	switch (param) {	case PIN_CONFIG_BIAS_DISABLE:// Check whether the pull-up/pull-down resistor is disabled		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:// Check whether the pull-up/pull-down resistor is valid, and get the current pull-up/pull-down resistor configuration		if (!rockchip_pinconf_pull_valid(info->ctrl, param))			return -ENOTSUPP;		if (rockchip_get_pull(bank, pin - bank->pin_base) != param)			return -EINVAL;		arg = 1;		break;	case PIN_CONFIG_OUTPUT:// Check whether the pin is configured as GPIO output mode		rc = rockchip_get_mux(bank, pin - bank->pin_base);		if (rc != RK_FUNC_GPIO)			return -EINVAL;		if (!gpio || !gpio->get) {			arg = 0;			break;		}		// Get the output state of the pin		rc = gpio->get(gpio, pin - bank->pin_base);		if (rc < 0)			return rc;		arg = rc ? 1 : 0;		break;	case PIN_CONFIG_DRIVE_STRENGTH:		/* rk3288 is the first with per-pin drive-strength */        	// Per-pin independent drive strength setting supported only on certain chips (e.g., rk3288).		if (!info->ctrl->drv_calc_reg)			return -ENOTSUPP;		// Get the drive strength configuration of the pin		rc = rockchip_get_drive_perpin(bank, pin - bank->pin_base);		if (rc < 0)			return rc;		arg = rc;		break;	case PIN_CONFIG_INPUT_SCHMITT_ENABLE:        	// Schmitt trigger setting supported only on certain chips.		if (!info->ctrl->schmitt_calc_reg)			return -ENOTSUPP;		// Get the Schmitt trigger configuration of the pin.		rc = rockchip_get_schmitt(bank, pin - bank->pin_base);		if (rc < 0)			return rc;		arg = rc;		break;	case PIN_CONFIG_SLEW_RATE:        	// Pin drive rate setting supported only on certain chips.		if (!info->ctrl->slew_rate_calc_reg)			return -ENOTSUPP;		// Get the drive rate configuration of the pin.		rc = rockchip_get_slew_rate(bank, pin - bank->pin_base);		if (rc < 0)			return rc;		arg = rc;		break;	default:// Unsupported configuration parameter.		return -ENOTSUPP;	}	*config = pinconf_to_config_packed(param, arg);	return 0;}

    pin_config_set

    Set pin configuration information.

    123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
    /* set the pin config settings for a specified pin */static int rockchip_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin,				unsigned long *configs, unsigned num_configs){	struct rockchip_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);	struct rockchip_pin_bank *bank = pin_to_bank(info, pin);	struct gpio_chip *gpio = &bank->gpio_chip;	enum pin_config_param param;	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.			 */            		/*			 * Check GPIO whether the driver has been probed。			 * Lock to ensure GPIO probe completion or GPIO the driver has not been probed yet。			 */			mutex_lock(&bank->deferred_lock);			if (!gpio || !gpio->direction_output) {                		// If the driver has not been probed yet, defer processing of the configuration information and return.				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:            		// Disable pull-up/pull-down resistors.			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:            		// Check whether the pull-up/pull-down resistors are valid.			if (!rockchip_pinconf_pull_valid(info->ctrl, param))				return -ENOTSUPP;			if (!arg)				return -EINVAL;			// Set the pull-up/pull-down resistors.			rc = rockchip_set_pull(bank, pin - bank->pin_base,				param);			if (rc)				return rc;			break;		case PIN_CONFIG_OUTPUT:            		// Set the pin multiplexing function to GPIO.			rc = rockchip_set_mux(bank, pin - bank->pin_base,					      RK_FUNC_GPIO);			if (rc != RK_FUNC_GPIO)				return -EINVAL;			// Set the pin to output mode.			rc = gpio->direction_output(gpio, pin - bank->pin_base,						    arg);			if (rc)				return rc;			break;		case PIN_CONFIG_INPUT_ENABLE:            		// Set the pin multiplexing function to GPIO.			rc = rockchip_set_mux(bank, pin - bank->pin_base,					      RK_FUNC_GPIO);			if (rc != RK_FUNC_GPIO)				return -EINVAL;			// Set the pin to input mode.			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 */            		// Per-pin independent drive strength setting supported only on certain chips (e.g., rk3288).			if (!info->ctrl->drv_calc_reg)				return -ENOTSUPP;			// Set the drive strength of the pin.			rc = rockchip_set_drive_perpin(bank,						pin - bank->pin_base, arg);			if (rc < 0)				return rc;			break;		case PIN_CONFIG_INPUT_SCHMITT_ENABLE:            		// Schmitt trigger setting supported only on certain chips.			if (!info->ctrl->schmitt_calc_reg)				return -ENOTSUPP;			// Set the Schmitt trigger mode of the pin.			rc = rockchip_set_schmitt(bank,						  pin - bank->pin_base, arg);			if (rc < 0)				return rc;			break;		case PIN_CONFIG_SLEW_RATE:            		// Pin drive rate setting supported only on certain chips.			if (!info->ctrl->slew_rate_calc_reg)				return -ENOTSUPP;			// Set the drive rate of the pin.			rc = rockchip_set_slew_rate(bank,						    pin - bank->pin_base, arg);			if (rc < 0)				return rc;			break;		default:// Unsupported configuration parameter.			return -ENOTSUPP;		}	} /* for each config */	return 0;}

    pinmux_ops

    1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
    /** * 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. */struct pinmux_ops {	// Check whether a pin can be set to be available for multiplexing.	int (*request) (struct pinctrl_dev *pctldev, unsigned offset);    	// The inverse of the request() callback, releases the pin after a request.	int (*free) (struct pinctrl_dev *pctldev, unsigned offset);    	// Return the number of selectable named functions in this pinmux driver.	int (*get_functions_count) (struct pinctrl_dev *pctldev);    	// Return the function name of the mux selector. The core calls this function to determine which mux setting a device should be mapped to.	const char *(*get_function_name) (struct pinctrl_dev *pctldev,					  unsigned selector);    	// Return a list of group names associated with a function selector (each referencing pins).	int (*get_function_groups) (struct pinctrl_dev *pctldev,				  unsigned selector,				  const char * const **groups,				  unsigned *num_groups);    	// Enable a specific mux function using a specific pin group.	int (*set_mux) (struct pinctrl_dev *pctldev, unsigned func_selector,			unsigned group_selector);    	// Request and enable GPIO on a specific pin.	int (*gpio_request_enable) (struct pinctrl_dev *pctldev,				    struct pinctrl_gpio_range *range,				    unsigned offset);    	// Release GPIO multiplexing on a specific pin.	void (*gpio_disable_free) (struct pinctrl_dev *pctldev,				   struct pinctrl_gpio_range *range,				   unsigned offset);    	// Configure differently depending on whether the GPIO is configured as input or output.	int (*gpio_set_direction) (struct pinctrl_dev *pctldev,				   struct pinctrl_gpio_range *range,				   unsigned offset,				   bool input);    	// Do not allow the same pin to be used for both GPIO and other functions. Strictly check gpio before approving a pin request._owner and mux_owner	bool strict;};

    struct pinmux_opsIs a structure used to describe pin multiplexing operations, a set of callback functions that a pinctrl driver must implement (if it supports pin multiplexing) to enable the pinctrl subsystem to:

    • Query which functions the SoC supports (e.g., I2C, UART, SPI…).
    • Query which pin groups can be used for each function.
    • Dynamically switch pin functions at runtime (e.g., change GPIO1_B0 from a regular GPIO to I2C._SCL)
    123456
    static const struct pinmux_ops rockchip_pmx_ops = {	.get_functions_count	= rockchip_pmx_get_funcs_count,	.get_function_name	= rockchip_pmx_get_func_name,	.get_function_groups	= rockchip_pmx_get_groups,	.set_mux		= rockchip_pmx_set,};

    get_functions_count

    Return the number of selectable named functions in this pin controller driver.

    123456
    static int rockchip_pmx_get_funcs_count(struct pinctrl_dev *pctldev){	struct rockchip_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);	return info->nfunctions;// Return the number of pin muxing functions.}

    get_function_name

    Return the function name of the mux selector.

    1234567
    static const char *rockchip_pmx_get_func_name(struct pinctrl_dev *pctldev,					  unsigned selector){	struct rockchip_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);	return info->functions[selector].name;// Return the name of the pin muxing function.}

    get_function_groups

    Return a set of group names associated with a function selector (each referencing pins).

    1234567891011
    static int rockchip_pmx_get_groups(struct pinctrl_dev *pctldev,				unsigned selector, const char * const **groups,				unsigned * const num_groups){	struct rockchip_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);	*groups = info->functions[selector].groups;// Return the array of pin groups corresponding to the pin muxing function.	*num_groups = info->functions[selector].ngroups;// Return the number of pin groups.	return 0;}

    set_mux

    Used to enable a specific muxing function.

    123456789101112131415161718192021222324252627282930313233343536373839
    static int rockchip_pmx_set(struct pinctrl_dev *pctldev, unsigned selector,			    unsigned group){	struct rockchip_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);	const unsigned int *pins = info->groups[group].pins;	const struct rockchip_pin_config *data = info->groups[group].data;	struct device *dev = info->dev;	struct rockchip_pin_bank *bank;	int cnt, ret = 0;	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 each pin in the selected pin group.,Program the corresponding pin function number into the configuration 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 */        	/* Restore the already set pin settings. */		for (cnt--; cnt >= 0 && !data[cnt].func; cnt--)			rockchip_set_mux(bank, pins[cnt] - bank->pin_base, 0);		return ret;	}	return 0;}

    When is the pin multiplexing relationship set?

    • Conjecture 1

    The first conjecture is that pinctrl pin multiplexing is performed when loading the LED driver. After the device tree of the LED light matches the driver, it enters the probe
    function, and before this, it will executedrivers/base/dd.cin the filereally_probesub-function in the functionpinctrl_bind_pins, this function binds pins for the given device, and during the binding process selects and sets the appropriate pinctrl state. For specific binding details, you can refer to the previous chapters.

    • Conjecture 2

    The second conjecture is that the pin multiplexing is completed when loading the pinctrl driver, because the pinctrl subsystem also conforms to the device model specification and will also execute the corresponding probe function, so similarly, when loading the pinctrl driver, it will also executedrivers/base/dd.cin the filereally_probesub-function in the functionpinctrl_bind_pins, then will the pinctrl pin multiplexing settings be performed at this time? Next, we will conduct an in-depth analysis of this.

    Take the device tree node of the 485 control pin and the corresponding pinctrl device tree node as an example. The 485 device tree content to be added is as follows.

    123456789101112131415
    	rk_485_ctl: rk-485-ctl {		compatible = "topeet,rs485_ctl";		gpios = <&gpio0 22 GPIO_ACTIVE_HIGH>;		pinctrl-names = "default";		pinctrl-0 = <&rk_485_gpio>;	};&pinctrl {	rk_485{		rk_485_gpio:rk-485-gpio {			rockchip,pins = <3 13 RK_FUNC_GPIO &pcfg_pull_none>;		};	};};

    After the 485 device tree written above successfully matches the driver, it will enter the probe function in the corresponding driver. In the probe function, the 485 enable pin described in the device tree can be pulled high and low, thereby controlling the reception and transmission of 485.

    So it can be guessed that before entering the driver’s probe function, the pinctrl subsystem has already been used to multiplex the pins. In the device model, we already know that the probe function in the driver is located in the kernel source directory.drivers/base/dd.cloaded and executed in the file, and then findreally_probethe code related to the probe function loading in the function

    really_probe()

    123456789101112131415161718192021222324252627282930313233343536373839404142434445
    static int really_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;// Set the device's driver pointer to the current driver.	/* If using pinctrl, bind pins now before probing */    	/* If pinctrl is used, bind pins before probing. */	ret = pinctrl_bind_pins(dev);// Bind the device's pins.	if (ret)		goto pinctrl_bind_failed;	...}

    If pinctrl is enabled, it will call the function on line 39pinctrl_bind_pins()to bind the device pins, and then follow the clue to jump topinctrl_bind_pinsfunction

    pinctrl_bind_pins()

    123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
    // drivers/base/pinctrl.c/** * pinctrl_bind_pins() - called by the device core before probe * @dev: the device that is just about to probe */int pinctrl_bind_pins(struct device *dev){	int ret;	// Check whether the device reuses the node.	if (dev->of_node_reused)		return 0;	// Allocate memory space for the device's pins	dev->pins = devm_kzalloc(dev, sizeof(*(dev->pins)), GFP_KERNEL);	if (!dev->pins)		return -ENOMEM;    	// Get the device's pinctrl handle	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;	}	// Find the device's default pinctrl state	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;	}	// Find the device's initialization pinctrl state	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 */        	/* It is perfectly legal not to provide this state */		dev_dbg(dev, "no init pinctrl state\n");		// Select the default pinctrl state		ret = pinctrl_select_state(dev->pins->p,					   dev->pins->default_state);	} else {        	// Select the initialization pinctrl state		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>	 */    	/*	 * If power management is enabled,We will also look for optional sleep and idle pin states,Its semantics are in	 * <linux/pinctrl/pinctrl-state.h> defined in	 */	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 */        	/* It is perfectly legal not to provide this state */		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 */        	/* It is perfectly legal not to provide this state */		dev_dbg(dev, "no idle pinctrl state\n");#endif	return 0;	/*	 * 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.	 */    	/* If no pinctrl handle or default state is found for this device,	 * Let us explicitly release the pin container in the device,Because there is no point in keeping it。    	 */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 deferred */		return ret;	/* Return serious errors */	if (ret == -EINVAL)/* Return a fatal error */		return ret;	/* We ignore errors like -ENOENT meaning no pinctrl state */	/* We ignore errors such as -ENOENT, indicating that there is no pinctrl state */	return 0;}

    Line 19dev->pins->p = devm_pinctrl_get(dev);Get the device’s pinctrl handle,devis of typestruct device, forstruct deviceStructure: which containsstruct dev_pin_info *pins;The member represents the pin information of the device

    12345678910111213141516171819202122232425262728293031323334353637
    struct device {	struct kobject kobj;// Kernel object, used for device management	struct device		*parent;// Pointer to parent device	struct device_private	*p;// Private data pointer	const char		*init_name; /* initial name of the device */ // Initial Device Name	const struct device_type *type;// Device Type	struct bus_type	*bus;		/* type of bus device is on */ // Bus type of the device	struct device_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	struct mutex		lockdep_mutex;#endif	struct mutex		mutex;	/* mutex to synchronize calls to* its driver.*/	struct dev_links_info	links;	struct dev_pm_info	power;	struct dev_pm_domain	*pm_domain;#ifdef CONFIG_ENERGY_MODEL	struct em_perf_domain	*em_pd;#endif#ifdef CONFIG_GENERIC_MSI_IRQ_DOMAIN	struct irq_domain	*msi_domain; // Generic MSI IRQ domain for devices#endif#ifdef CONFIG_PINCTRL	struct dev_pin_info	*pins;// Device pin information#endif    ...}

    struct dev_pin_info

    123456789101112131415161718
    /** * 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 */struct dev_pin_info {	struct pinctrl *p;                 // pin controller pointer	struct pinctrl_state *default_state;// default state pointer	struct pinctrl_state *init_state;// Initialize state pointer#ifdef CONFIG_PM	struct pinctrl_state *sleep_state;// Sleep state pointer is only available when power management is supported.	struct pinctrl_state *idle_state;// Idle state pointer is only available when power management is supported.#endif};
    • struct pinctrl *p: Pin controller pointer. This pointer points to the pin controller object used by the device, and is used to control and configure the device’s pins.

    • struct pinctrl_state *default_state: Default state pointer. This pointer points to the device’s default pin configuration state, indicating the pin configuration during normal operation.

    • struct pinctrl_state *init_state: Initialization state pointer. This pointer points to the device’s initialization pin configuration state, indicating the pin configuration during the initialization phase.

    • struct pinctrl_state *sleep_state: Sleep state pointer (only available when power management is supported). This pointer points to the device’s pin configuration state, indicating the pin configuration when the device enters the sleep state.

    • struct pinctrl_state *idle_state: Idle state pointer (only available when power management is supported). This pointer points to the pin configuration state of the device, indicating the pin configuration when the device is in the idle state.

    Still using the 485 control pin as an example

    123456789101112131415
    	rk_485_ctl: rk-485-ctl {		compatible = "topeet,rs485_ctl";		gpios = <&gpio0 22 GPIO_ACTIVE_HIGH>;		pinctrl-names = "default";		pinctrl-0 = <&rk_485_gpio>;	};&pinctrl {	rk_485{		rk_485_gpio:rk-485-gpio {			rockchip,pins = <3 13 RK_FUNC_GPIO &pcfg_pull_none>;		};	};};

    of the 4th row among thempinctrl-namesThe attribute specifies the pin controller used by the device.default, i.e., the one on line 5pinctrl-0, andpinctrl-0The value is in the pinctrl node.rk_485_gpio, sostruct pinctrl_state *default_stateThis default state structure pointer will be used to store the pin multiplexing information of 11 lines, and as mentioned in the previous chapter, the pinctrl node in the device tree will be converted topinctrl_mapStruct, thenstruct pinctrl_state *default_statewill inevitablypinctrl_mapestablish a connection with the structure.

    devm_pinctrl_get()

    pinctrl_bind_pins()In the function, throughdev->pins->p = devm_pinctrl_get(dev);to obtain the device’s pinctrl handle, anddevm_pinctrl_get()The function is defined as follows:

    12345678910111213141516171819202122232425262728293031
    // 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){	struct pinctrl **ptr, *p;	// Allocate memory for the pointer that stores the pin controller handle.	ptr = devres_alloc(devm_pinctrl_release, sizeof(*ptr), GFP_KERNEL);	if (!ptr)		return ERR_PTR(-ENOMEM);    	// Get the device's pin controller handle.	p = pinctrl_get(dev);	if (!IS_ERR(p)) {        	// If successful, store the pin controller handle in the pointer.		*ptr = p;        	// Add the pointer to the device resources.		devres_add(dev, ptr);	} else {        	// If acquisition fails, free the previously allocated pointer memory.		devres_free(ptr);	}	return p;}EXPORT_SYMBOL_GPL(devm_pinctrl_get);

    Line 18, throughpinctrl_get()obtains the pin controller handle.

    pinctrl_get()

    devm_pinctrl_get()In the function, throughpinctrl_get()the function obtains the pin controller handle.

    1234567891011121314151617181920212223242526272829303132
    // 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){	struct pinctrl *p;	// Check whether the device pointer is NULL.	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.	 */    	/*	 * Check whether there are other components.(such as the device core)has already obtained the pin controller handle of this device.。	 * In this case,,return another pointer to that handle.。	 */	p = find_pinctrl(dev);	if (p) {		dev_dbg(dev, "obtain a copy of previously claimed pinctrl\n");		kref_get(&p->users);		return p;	}	// Create and return the device's pin controller handle.	return create_pinctrl(dev, NULL);}EXPORT_SYMBOL_GPL(pinctrl_get);

    In the return value, usecreate_pinctrlthe function, which creates and returns the device’s pin controller handle. Note that the second parameter is NULL.

    create_pinctrl()

    pinctrl_get()Finally, callcreate_pinctrl()create and return the device’s pin controller handle, with the first parameter passed being the device matched by the current driver.struct device, andstruct pinctrl_dev *pctldevthe value is NULL

    123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
    // drivers/pinctrl/core.cstatic struct pinctrl *create_pinctrl(struct device *dev,				      struct pinctrl_dev *pctldev){	struct pinctrl *p;	const char *devname;	struct pinctrl_maps *maps_node;	int i;	const struct pinctrl_map *map;	int ret;	/*	 * 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()	 */    	/*	 * Allocate a state holder for each mapping struct pinctrl。	 * This is when using pinctrl_get() The object that the consumer will obtain when requesting a pin control handle。	 */	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 */    	/* Traverse the pin control mappings to locate the correct mapping */	for_each_maps(maps_node, i, map) {		/* Map must be for this device */		if (strcmp(map->dev_name, devname))/* The mapping must apply to this device */			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.		 */		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.		 */		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 */        	/* If an error other than deferral occurs, return here */		pinctrl_free(p, false);		return ERR_PTR(ret);	}	kref_init(&p->users);	/* Add the pinctrl handle to the global list */    	/* Add the pin control handle to the global list */	mutex_lock(&pinctrl_list_mutex);	list_add_tail(&p->node, &pinctrl_list);	mutex_unlock(&pinctrl_list_mutex);	return p;}

    Three important structures:

    • struct pinctrl
    • struct pinctrl_maps
    • struct pinctrl_map

    Line 28 callsret = pinctrl_dt_to_map(p, pctldev);Convert the pin mapping information defined in the device tree intostruct pinctrl_mapStructure

    for_each_mapsdefined as follows

    123456789
    // Macro definition: used to traverse each mapping table entry in the mapping table linked list// _maps_node_: pointer to the mapping table node used during traversal// _i_: counter variable used during traversal// _map_: pointer to the mapping table entry used during traversal#define for_each_maps(_maps_node_, _i_, _map_) \	list_for_each_entry(_maps_node_, &pinctrl_maps, node) \ // Traverse each node in the mapping table linked list		for (_i_ = 0, _map_ = &_maps_node_->maps[_i_]; \ // Initialize the counter and the mapping table entry pointer			_i_ < _maps_node_->num_maps; \ // Loop condition: the counter is less than the number of mapping table entries in the current node			_i_++, _map_ = &_maps_node_->maps[_i_]) // Each iteration increments the counter and updates the mapping table entry pointer

    Important data structures

    struct pinctrl

    struct pinctrlThe structure is used to represent a pin controller.

    The pin controller is a component in a hardware system that manages and controls pins (GPIO). It is responsible for configuring pin functions, electrical properties, etc. This structure is defined in the kernel source directory’sdrivers/pinctrl/core.hfile.

    12345678910111213141516171819
    /** * 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 */struct pinctrl {	struct list_head node;		// Linked list node used to add the pin controller to the global list	struct device *dev;		// Associated device	struct list_head states; 	// Linked list storing pin configuration states, used to track different pin configuration states	struct pinctrl_state *state;// Currently applied pin configuration state	struct list_head dt_maps;	// Linked list storing pin mapping information defined in the device tree	struct kref users;		// Reference count of the pin controller, used to track the number of references to the pin controller};
    struct pinctrl_maps

    struct pinctrl_mapsvariable of typemaps_nodeUsed to iterate over pin control mappings. Pin controller mappings describe the correspondence between the functions and configurations of different pin controllers and actual hardware pins. This structure is defined in the kernel source directory’sdrivers/pinctrl/core.hfile.

    1234567891011
    /** * 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 */struct pinctrl_maps {	struct list_head node; 		// Pin controller mapping linked list node, used to add the mapping to the global list	const struct pinctrl_map *maps;	// Pointer to the pin controller mapping array	unsigned num_maps;		// Number of mappings in the pin controller mapping array};

    wherepinctrl_mapThe structure isdt_node_to_mapcreated in

    pinctrl_dt_to_map()

    create_pinctrl()by callingret = pinctrl_dt_to_map(p, pctldev);The function converts the pin mapping information defined in the device tree intostruct pinctrl_mapstructure, and adds it top->dt_mapsthe linked list.

    123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
    // drivers/pinctrl/devicetree.cint pinctrl_dt_to_map(struct pinctrl *p, struct pinctrl_dev *pctldev){	struct device_node *np = p->dev->of_node;// Get the device tree node of the device associated with the pin controller	int state, ret;	char *propname;	struct property *prop;	const char *statename;	const __be32 *list;	int size, config;	phandle phandle;	struct device_node *np_config;	/* CONFIG_OF enabled, p->dev not instantiated from DT */    	/* If CONFIG_OF is enabled, and p->dev is not instantiated from the device tree */	if (!np) {		if (of_have_populated_dt())			dev_dbg(p->dev,				"no of_node; not parsing pinctrl DT\n");		return 0;	}	/* We may store pointers to property names within the node */    	/* pointer to the property name stored inside the node */	of_node_get(np);//Increase the reference count of the device tree node to ensure that the node will not be released during parsing	/* For each defined state ID */    	/* For each defined state ID */	for (state = 0; ; state++) {		/* Retrieve the pinctrl-* property */        	/* Get the pinctrl-* property */		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 */        	/* Determine whether the pinctrl-names property has named the state */		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.		 */		if (ret < 0)			statename = prop->name + strlen("pinctrl-");		/* For every referenced pin configuration node in it */        	/* For each referenced pin configuration node in it */		for (config = 0; config < size; config++) {			phandle = be32_to_cpup(list++);			/* Look up the pin configuration node */            		/* Find 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 */            		/* 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 there is no entry in the device tree, generate a dummy state table entry */		if (!size) {			ret = dt_remember_dummy_state(p, statename);			if (ret < 0)				goto err;		}	}	return 0;err:	pinctrl_dt_free_maps(p);	return ret;}

    For each defined state ID, the loop that parses the pin controller’s mapping information specifically performs the following steps:

    • Construct the property name string.propname, for example"pinctrl-0""pinctrl-1"etc.
    • useof_find_propertyThe function gets the property in the device tree node nppropnamevalue, and gets the size of the property value.size. If the property does not exist, determine whether it is the first state ID. If so, release the node reference and return. -ENODEVIndicates that there is no valid pinctrl description in the device tree node. Otherwise, break out of the loop.
    • Convert the property value into a pointer list, and compute the size of the list.
    • If the device tree’spinctrl-namesproperty names the state, then useof_property_read_string_indexfunction reads the property value and stores the state name in statenamethe variable. Otherwise, pointstatenameto a part of the property name, i.e., remove"pinctrl-"prefix.
    • For each referenced pin configuration node, perform the following steps:
      • willlistThe value pointed to by the pointerphandleis converted to native byte order.
      • useof_find_node_by_phandleThe function, based onphandlelooks up the pin configuration node and stores it innp_configthe variable. If the pin configuration node is not found, print an error message and return-EINVAL
      • Calldt_to_map_one_configfunction parses the pin configuration node’s information into a pinctrl mapping and stores it inpctldevMiddle.
      • Decrement the reference count of the pin configuration node.
      • If there is no entry in the device tree, generate a dummy state table entry for subsequent processing.

    wheredt_to_map_one_configThis function requires special attention. It parses the pin controller mapping table from the device tree node and stores it. The specific content of this function is as follows:

    dt_to_map_one_config()
    1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
    static int dt_to_map_one_config(struct pinctrl *p,				struct pinctrl_dev *hog_pctldev,				const char *statename,				struct device_node *np_config){	struct pinctrl_dev *pctldev = NULL;	struct device_node *np_pctldev;	const struct pinctrl_ops *ops;	int ret;	struct pinctrl_map *map;	unsigned num_maps;	bool allow_default = false;	/* Find the pin controller containing np_config */    	/* Find the pin controller containing np_config */	np_pctldev = of_node_get(np_config);	for (;;) {        	/* If default configuration is not allowed, read the pinctrl-use-default property */		if (!allow_default)			allow_default = of_property_read_bool(np_pctldev,							      "pinctrl-use-default");		/* Get the parent node of np_pctldev */		np_pctldev = of_get_next_parent(np_pctldev);        	/* If there is no parent node or the parent node is the root node, release the np_pctldev reference and return */		if (!np_pctldev || of_node_is_root(np_pctldev)) {			of_node_put(np_pctldev);            		/* Check whether to defer probing the driver state */			ret = driver_deferred_probe_check_state(p->dev);			/* keep deferring if modules are enabled */            		/* If the module is enabled and default configuration is not allowed, and the return value is -ENODEV, defer probing. */			if (IS_ENABLED(CONFIG_MODULES) && !allow_default && ret < 0)				ret = -EPROBE_DEFER;			return ret;		}		/* If we're creating a hog we can use the passed pctldev */        	/* If a hog is being created, the passed pctldev can be used */		if (hog_pctldev && (np_pctldev == p->dev->of_node)) {			pctldev = hog_pctldev;			break;		}        	/* via np_pctldev obtains pinctrl_dev structure */		pctldev = get_pinctrl_dev_from_of_node(np_pctldev);        	/* If the pinctrl_dev structure is obtained, break out of the loop */		if (pctldev)			break;		/* Do not defer probing of hogs (circular loop) */        	/* Do not defer probing hogs (loop) */		if (np_pctldev == p->dev->of_node) {			of_node_put(np_pctldev);			return -ENODEV;		}	}	of_node_put(np_pctldev);	/*	 * Call pinctrl driver to parse device tree node, and	 * generate mapping table entries	 */	// Call the pinctrl driver to parse the device tree node and generate mapping table entries	ops = pctldev->desc->pctlops;    	/* Check whether the pinctrl driver supports device tree, i.e., whether it implements dt_node_to_map method. If not supported, return an error code. */	if (!ops->dt_node_to_map) {		dev_err(p->dev, "pctldev %s doesn't support DT\n",			dev_name(pctldev->dev));		return -ENODEV;	}    	/* Call the pinctrl driver's dt_node_to_map method */	ret = ops->dt_node_to_map(pctldev, np_config, &map, &num_maps);	if (ret < 0)		return ret;	else if (num_maps == 0) {		/*		 * If we have no valid maps (maybe caused by empty pinctrl node		 * or typing error) ther is no need remember this, so just		 * return.		 */		dev_info(p->dev,			 "there is not valid maps for state %s\n", statename);		return 0;	}	/* Stash the mapping table chunk away for later use */    	/* Store the mapping table block for later use */	return dt_remember_or_free_map(p, statename, pctldev, map, num_maps);}

    Line 70 calls the pin controller’sdt_node_to_mapmethod, converting the device tree nodenp_configinto mapping table entries. This method parses the device tree node and generates mapping table entries based on the node information. The specific conversion process is implemented by each pinctrl driver.

    dt_remember_or_free_map()

    dt_to_map_one_configThe function is used to parse the pin controller mapping table from the device tree node and store it, and the storage operation is performed by the functiondt_remember_or_free_mapis completed.

    Function parameter passing:

    • p: points tostruct pinctrlA pointer to the structure, representing the context of the pin controller.
    • statename: Pointer to the state name, indicating the name of the state to set.
    • pctldev: points tostruct pinctrl_devA pointer to the structure, representing the pin controller device.
    • map: points tostruct pinctrl_mapA pointer to an array of structures, representing the mapping table entries obtained from parsing.
    • num_maps: Indicates the number of entries in the mapping table.
    1234567891011121314151617181920212223242526272829303132333435363738394041
    static int dt_remember_or_free_map(struct pinctrl *p, const char *statename,				   struct pinctrl_dev *pctldev,				   struct pinctrl_map *map, unsigned num_maps){	int i;	struct pinctrl_dt_map *dt_map;	/* Initialize common mapping table entry fields */    	// Iterate over the array of map entries, initializing common fields for each entry.	for (i = 0; i < num_maps; i++) {		const char *devname;		// Copy the name of the pin controller device using the kstrdup_const function, and assign the returned pointer to devname.		devname = kstrdup_const(dev_name(p->dev), GFP_KERNEL);		if (!devname)			goto err_free_map;		// Set the device name, state name, and controller device name of the mapping table entry.		map[i].dev_name = devname;		map[i].name = statename;		if (pctldev)			map[i].ctrl_dev_name = dev_name(pctldev->dev);	}	/* Remember the converted mapping table entries */    	/* Record the converted mapping table entries */	dt_map = kzalloc(sizeof(*dt_map), GFP_KERNEL);//Use kzalloc to allocate memory space, and assign the returned pointer to dt_map.	if (!dt_map)		goto err_free_map;	// The passed-in pctldev, map, and num_Assign maps to dt respectively_the corresponding field of map	dt_map->pctldev = pctldev;	dt_map->map = map;	dt_map->num_maps = num_maps;	list_add_tail(&dt_map->node, &p->dt_maps);// Use list_add_tail function takes dt_map added to p->dt_in the maps linked list	/* Register mapping table entry */	return pinctrl_register_mappings(map, num_maps);err_free_map:    	/* Release mapping table entry memory */	dt_free_map(pctldev, map, num_maps);	return -ENOMEM;}
    struct pinctrl_dt_map
    123456
    struct pinctrl_dt_map {	struct list_head node;//Used to add the mapping table structure to the dt_maps linked list of pinctrl.	struct pinctrl_dev *pctldev;// Pin Controller Device	struct pinctrl_map *map;// Mapping table entry array	unsigned num_maps;//Mapping table entry count};
    pinctrl_register_mappings()

    dt_remember_or_free_map()Last usedpinctrl_register_mappings()The function registers mapping table entries. It registers mapping table entries into the pinctrl subsystem so that pin configuration and management can be performed through related interfaces later.

    123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475
    /** * 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: pointer to the mapping table entry array// num_maps: number of mapping table entriesint pinctrl_register_mappings(const struct pinctrl_map *maps,			      unsigned num_maps){	int i, ret;	struct pinctrl_maps *maps_node;	pr_debug("add %u pinctrl maps\n", num_maps);	/* First sanity check the new mapping */    	/* First, perform a validity check on the new mapping table. */	for (i = 0; i < num_maps; i++) {        	// Check whether the device name exists.		if (!maps[i].dev_name) {			pr_err("failed to register map %s (%d): no device given\n",			       maps[i].name, i);			return -EINVAL;		}		// Check whether the mapping table name exists.		if (!maps[i].name) {			pr_err("failed to register map %d: no map name given\n",			       i);			return -EINVAL;		}		// For pin mapping type and configuration mapping type, check whether the pin control device name exists.		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:// For virtual state mapping type, no validation is performed.			break;		case PIN_MAP_TYPE_MUX_GROUP:// For mux group mapping type, perform pin mux mapping validation.			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:// For configuration mapping type, perform pin configuration mapping validation.			ret = pinconf_validate_map(&maps[i], i);			if (ret < 0)				return ret;			break;		default:// For invalid mapping type, return an error.			pr_err("failed to register map %s (%d): invalid type given\n",			       maps[i].name, i);			return -EINVAL;		}	}	// Allocate memory for the mapping table node.	maps_node = kzalloc(sizeof(*maps_node), GFP_KERNEL);	if (!maps_node)		return -ENOMEM;	// Set the mapping table and mapping table count of the mapping table node.	maps_node->maps = maps;	maps_node->num_maps = num_maps;	// Lock and insert the mapping table node at the end of the mapping table linked list.	mutex_lock(&pinctrl_maps_mutex);	list_add_tail(&maps_node->node, &pinctrl_maps);	mutex_unlock(&pinctrl_maps_mutex);	return 0;}EXPORT_SYMBOL_GPL(pinctrl_register_mappings);

    It can be seenpinctrl_register_mappingsThe function is used to register a mapping table for a pin controller.pinctrl_mapsIt performs some parameter validity checks and validation, and inserts the mapping table node into the mapping table linked list.

    add_setting()

    create_pinctrlIn the function, throughret = add_setting(p, pctldev, map);Add the mapping to the pin controller.

    1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071
    static int add_setting(struct pinctrl *p, struct pinctrl_dev *pctldev,		       const struct pinctrl_map *map){	struct pinctrl_state *state;// pinctrl_state object pointer	struct pinctrl_setting *setting;// pinctrl_setting object pointer	int ret;    	// Find pinctrl_state, if it does not exist, create a new pinctrl._state	state = find_state(p, map->name);	if (!state)		state = create_state(p, map->name);	if (IS_ERR(state))		return PTR_ERR(state);    	// If the mapping type is a virtual state mapping type, return directly.	if (map->type == PIN_MAP_TYPE_DUMMY_STATE)		return 0;    	// Allocate memory space for pinctrl_setting.	setting = kzalloc(sizeof(*setting), GFP_KERNEL);	if (!setting)		return -ENOMEM;	setting->type = map->type;// Set the mapping type of pinctrl_setting.	if (pctldev)// Set the pin control device of 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 the pin control device does not exist, return an error.		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;	}	// Set the device name of pinctrl_setting.	setting->dev_name = map->dev_name;	switch (map->type) {	case PIN_MAP_TYPE_MUX_GROUP:        	// For the mux group mapping type, execute pinmux_map to pinctrl_conversion of setting		ret = pinmux_map_to_setting(map, setting);		break;	case PIN_MAP_TYPE_CONFIGS_PIN:	case PIN_MAP_TYPE_CONFIGS_GROUP:        	// For the configuration mapping type, execute pinconf_map to pinctrl_conversion of setting		ret = pinconf_map_to_setting(map, setting);		break;	default:		ret = -EINVAL;		break;	}	if (ret < 0) {		kfree(setting);		return ret;	}	// Insert pinctrl_setting at the end of the state object's setting list.	list_add_tail(&setting->node, &state->settings);	return 0;}

    It can be seen:

    • For the mux group mapping type (PIN_MAP_TYPE_MUX_GROUP), callpinmux_map_to_settingfunction to execute the conversion of pin mux mapping to setting object.

    • For the configuration mapping type (PIN_MAP_TYPE_CONFIGS_PINorPIN_MAP_TYPE_CONFIGS_GROUP), callpinconf_map_to_settingthe function to execute the conversion of the pin configuration mapping to the settings object.

    add_settingThe ultimate purpose of the function is to pass the incomingconst struct pinctrl_map *mapparameter values intostruct pinctrl_settingvariables of type, thereby further extractingpinctrl_mapthe content in the structure type variable.

    struct pinctrl_state
    123456789101112
    /** * 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;// Linked list node, used to connect the state object to the state list of the pin controller object.	const char *name;// Pointer to the name string of the state object	struct list_head settings;// Linked list of pinctrl_setting objects, containing all setting objects for this state};
    struct pinctrl_setting
    1234567891011121314151617181920
    // 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 */struct pinctrl_setting {	struct list_head node; // Linked list node, used to connect the setting object to the setting list of the state object	enum pinctrl_map_type type; // Mapping type, indicating the type of the setting object	struct pinctrl_dev *pctldev; // Pointer to the pin control device object	const char *dev_name; // Pointer to the device name string	union {		struct pinctrl_setting_mux mux; // Data structure for the mux group mapping type		struct pinctrl_setting_configs configs; // Data structure for the config mapping type	} data;};
    create_state()

    add_setting()In the function, based on the name of the mapping table entry, usefind_state()The function looks up the corresponding state object in the pin controller object. Since we have not set the state object before, it enters the second if judgment, throughstate = create_state(p, map->name)Create a state

    123456789101112131415161718
    static struct pinctrl_state *create_state(struct pinctrl *p,					  const char *name){	struct pinctrl_state *state;	// Allocate memory for the pinctrl_state structure	state = kzalloc(sizeof(*state), GFP_KERNEL);	if (!state)		return ERR_PTR(-ENOMEM);	// Set the name of the state	state->name = name;    	// Initialize the state's setting list	INIT_LIST_HEAD(&state->settings);	// Add the state to the pinctrl's state linked list	list_add_tail(&state->node, &p->states);	return state;}
    pinmux_map_to_setting()

    add_setting()In the function, for the mux group mapping type (PIN_MAP_TYPE_MUX_GROUP), callpinmux_map_to_settingfunction to execute the conversion of pin mux mapping to setting object.

    12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364
    // drivers/pinctrl/pinmux.cint pinmux_map_to_setting(const struct pinctrl_map *map,			  struct pinctrl_setting *setting){	struct pinctrl_dev *pctldev = setting->pctldev;// Get the pin control device pointer	const struct pinmux_ops *pmxops = pctldev->desc->pmxops;// Get the pin mux operation pointer	char const * const *groups; // Pin mux group array	unsigned num_groups; // Pin mux group count	int ret;	const char *group; // Pin mux group name	if (!pmxops) {// Check whether the pin control device supports pin mux operations		dev_err(pctldev->dev, "does not support mux function\n");		return -EINVAL;	}	// Convert the mux function name in the mapping table to a mux function selector, and store it in the data.mux.func field of the setting object	ret = pinmux_func_name_to_selector(pctldev, map->data.mux.function);	if (ret < 0) {		dev_err(pctldev->dev, "invalid function %s in map table\n",			map->data.mux.function);		return ret;	}	setting->data.mux.func = ret;    	// By calling the get function of the pin mux operation object_function_the groups function queries the mux group information corresponding to the mux function,    	// obtains the name array and count of the mux groups, and saves them in the groups and num_groups variables.	ret = pmxops->get_function_groups(pctldev, setting->data.mux.func,					  &groups, &num_groups);	if (ret < 0) {		dev_err(pctldev->dev, "can't query groups for function %s\n",			map->data.mux.function);		return ret;	}	if (!num_groups) {		dev_err(pctldev->dev,			"function %s can't be selected on any group\n",			map->data.mux.function);		return -EINVAL;	}	if (map->data.mux.group) {// According to the mux group name specified in the mapping table, or select the first mux group name, and find the corresponding index in the mux group array.		group = map->data.mux.group;		ret = match_string(groups, num_groups, group);		if (ret < 0) {			dev_err(pctldev->dev,				"invalid group \"%s\" for function \"%s\"\n",				group, map->data.mux.function);			return ret;		}	} else {		group = groups[0];	}	// By calling the pinctrl function of the pin control device object_get_group_selector    	// obtain the selector of the mux group and save it in the data.mux.group of the settings object	ret = pinctrl_get_group_selector(pctldev, group);	if (ret < 0) {		dev_err(pctldev->dev, "invalid group %s in map table\n",			map->data.mux.group);		return ret;	}	setting->data.mux.group = ret;// Set the mux group selector of the settings object.	return 0;}
    pinconf_map_to_setting()

    add_settingsIn the function, for the configuration mapping type (PIN_MAP_TYPE_CONFIGS_PINorPIN_MAP_TYPE_CONFIGS_GROUP), callpinconf_map_to_settingthe function to execute the conversion of the pin configuration mapping to the settings object.

    The function is topinctrl_mapconvert the pin configuration mapping topinctrl_settinga settings object.

    12345678910111213141516171819202122232425262728293031323334353637
    // drivers/pinctrl/pinconf.cint pinconf_map_to_setting(const struct pinctrl_map *map,			  struct pinctrl_setting *setting){	struct pinctrl_dev *pctldev = setting->pctldev;// Get the pin control device pointer	int pin;	switch (setting->type) {	case PIN_MAP_TYPE_CONFIGS_PIN:// For the configuration of a single pin		pin = pin_get_from_name(pctldev,					map->data.configs.group_or_pin);// Get the pin number by the pin name		if (pin < 0) {			dev_err(pctldev->dev, "could not map pin config for \"%s\"",				map->data.configs.group_or_pin);			return pin;		}		setting->data.configs.group_or_pin = pin;// Set the pin number of the settings object		break;	case PIN_MAP_TYPE_CONFIGS_GROUP:// For the configuration of a pin group		pin = pinctrl_get_group_selector(pctldev,					 map->data.configs.group_or_pin);// Get the selector of the pin group		if (pin < 0) {			dev_err(pctldev->dev, "could not map group config for \"%s\"",				map->data.configs.group_or_pin);			return pin;		}		setting->data.configs.group_or_pin = pin; // Set the pin group selector of the settings object		break;	default:		return -EINVAL;	}	setting->data.configs.num_configs = map->data.configs.num_configs;// Set the configuration count of the settings object	setting->data.configs.configs = map->data.configs.configs;// Set the configuration pointer of the settings object	return 0;}

    For the configuration of a single pin, by callingpin_get_from_namethe function, obtain the pin number according to the pin name in the mapping table, and set it to thedata.configs.group_or_pinfield of the settings object. If obtaining the pin number fails, return an error.

    For configuration targeting a pin group, it callspinctrl_get_group_selectorfunction, which obtains the pin group selector based on the pin group name in the mapping table, and sets it into the settings object’sdata.configs.group_or_pinfield.

    pinctrl_lookup_state()

    pinctrl_bind_pins()Through thedev->pins->default_state = pinctrl_lookup_state(dev->pins->p,PINCTRL_STATE_DEFAULT);Find the device’s default pinctrl state and assign it todev->pins->default_state. If the lookup fails, the function prints a debug message and sets the return value to 0, indicating to continue execution.

    12345678910111213141516171819202122232425262728
    /** * 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,						 const char *name){	struct pinctrl_state *state;	// Find the state object with the specified name in the state list.	state = find_state(p, name);	if (!state) {		if (pinctrl_dummy_state) {			/* create dummy state */            		/* Create a virtual state. */			dev_dbg(p->dev, "using pinctrl dummy state (%s)\n",				name);            		// If the specified state object is not found and a virtual state exists, create a virtual state object.			state = create_state(p, name);		} else           		// If the specified state object is not found and no virtual state exists, return the error pointer -ENODEV.			state = ERR_PTR(-ENODEV);	}	return state;}EXPORT_SYMBOL_GPL(pinctrl_lookup_state);

    pinctrl_select_state()

    pinctrl_bind_pins()usepinctrl_select_state()functionret = pinctrl_select_state(dev->pins->p,dev->pins->default_state);Select and switch to the specifiedpinctrl_state(pin control state)

    1234567891011121314
    /** * 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 */int pinctrl_select_state(struct pinctrl *p, struct pinctrl_state *state){	if (p->state == state)// If the current state is already the state to be selected, no operation is needed, and 0 is returned directly to indicate success.		return 0;	// Call pinctrl_commit_state function to apply and switch to the new state.	return pinctrl_commit_state(p, state);}EXPORT_SYMBOL_GPL(pinctrl_select_state);

    pinctrl_commit_state()

    123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
    /** * 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 */static int pinctrl_commit_state(struct pinctrl *p, struct pinctrl_state *state){	struct pinctrl_setting *setting, *setting2;	struct pinctrl_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.		 */       		/*		 * For each pin mux setting in the old state,,cancel SW the recorded mux owner of that pin group.。		 * Any pin groups still owned by the new state will be re-acquired in the pinmux_enable_setting() call in the loop below.。		 */		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 */    	/* Apply all settings of the new state. */	list_for_each_entry(setting, &state->settings, node) {		switch (setting->type) {		case PIN_MAP_TYPE_MUX_GROUP:            		// For pin mux settings (PIN_MAP_TYPE_MUX_GROUP), call pinmux_enable_setting() function to enable the setting.			ret = pinmux_enable_setting(setting);			break;		case PIN_MAP_TYPE_CONFIGS_PIN:		case PIN_MAP_TYPE_CONFIGS_GROUP:            		// For pin configuration settings (PIN_MAP_TYPE_CONFIGS_PIN or PIN_MAP_TYPE_CONFIGS_GROUP), call pinconf_apply_setting() function to apply the setting			ret = pinconf_apply_setting(setting);			break;		default:			ret = -EINVAL;			break;		}		if (ret < 0) {            		// If applying the setting fails, roll back the settings of the new state			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;	return 0;unapply_new_state:    	// Roll back the settings of the 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);	return ret;}

    pinctrl_commit_state()The function iterates over all settings of the new state and performs corresponding operations based on the type of setting:

    • For pin mux settings (PIN_MAP_TYPE_MUX_GROUP), callpinmux_enable_setting()function to enable the setting.

    • For pin configuration settings (PIN_MAP_TYPE_CONFIGS_PINorPIN_MAP_TYPE_CONFIGS_GROUP), callpinconf_apply_setting()function to apply the setting.

    • For other types of settings, an error code is returned (-EINVAL)。

    pinmux_enable_setting()
    12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
    //drivers/pinctrl/pinmux.cint pinmux_enable_setting(const struct pinctrl_setting *setting){	struct pinctrl_dev *pctldev = setting->pctldev;	const struct pinctrl_ops *pctlops = pctldev->desc->pctlops;	const struct pinmux_ops *ops = pctldev->desc->pmxops;	int ret = 0;	const unsigned *pins = NULL;	unsigned num_pins = 0;	int i;	struct pin_desc *desc;	// If pctlops->get_group_pins function exists, call it to get the pin information in the group, and store the pin information in the pins and num_pins variables	if (pctlops->get_group_pins)		ret = pctlops->get_group_pins(pctldev, setting->data.mux.group,					      &pins, &num_pins);	if (ret) {// If getting pin information fails, issue a warning and set num_pins to 0		const char *gname;		/* errors only affect debug data, so just warn */        	// The error only affects debug data, so only a warning is issued		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 */    	// Request the pins in the group one by one	for (i = 0; i < num_pins; i++) {        	// Use the pin_request function to request a pin, passing the pin controller device, pin number, device name, and other parameters		ret = pin_request(pctldev, pins[i], setting->dev_name, NULL);		if (ret) {			const char *gname;			const char *pname;			// After allocating the pin, use pin_desc_get function to get the pin descriptor, and point the mux setting pointer to the pin mux information.			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 */    	// After allocating the pin, 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);	}	// Call the ops->set_mux function to set the pin mux, passing the pin controller device, mux function, and group information to set the pin mux.	ret = ops->set_mux(pctldev, setting->data.mux.func,			   setting->data.mux.group);	if (ret)		goto err_set_mux;	return 0;err_set_mux:    	// If the mux setting fails, clear the mux setting	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 */    	// Release the requested pins when an error occurs	while (--i >= 0)		pin_free(pctldev, pins[i], NULL);	return ret;}
    pinconf_apply_setting()
    12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455
    // drivers/pinctrl/pinconf.cint pinconf_apply_setting(const struct pinctrl_setting *setting){	struct pinctrl_dev *pctldev = setting->pctldev;	const struct pinconf_ops *ops = pctldev->desc->confops;	int ret;	if (!ops) {// Check whether the pinconf operation function set exists		dev_err(pctldev->dev, "missing confops\n");		return -EINVAL;	}	// Select the corresponding operation according to the setting type.	switch (setting->type) {	case PIN_MAP_TYPE_CONFIGS_PIN://Indicates configuration settings for a single pin.		if (!ops->pin_config_set) {// Check whether the pin exists._config_set operation function			dev_err(pctldev->dev, "missing pin_config_set op\n");			return -EINVAL;		}        	// Call pin_config_The set function sets the configuration of a single pin.		ret = ops->pin_config_set(pctldev,				setting->data.configs.group_or_pin,				setting->data.configs.configs,				setting->data.configs.num_configs);		if (ret < 0) {			dev_err(pctldev->dev,				"pin_config_set op failed for pin %d\n",				setting->data.configs.group_or_pin);			return ret;		}		break;	case PIN_MAP_TYPE_CONFIGS_GROUP:// Indicates configuration settings for a pin group.		if (!ops->pin_config_group_set) {// Check whether the pin exists._config_group_set operation function			dev_err(pctldev->dev,				"missing pin_config_group_set op\n");			return -EINVAL;		}        	// Call pin_config_The group_set function sets the configuration of the pin group.		ret = ops->pin_config_group_set(pctldev,				setting->data.configs.group_or_pin,				setting->data.configs.configs,				setting->data.configs.num_configs);		if (ret < 0) {			dev_err(pctldev->dev,				"pin_config_group_set op failed for group %d\n",				setting->data.configs.group_or_pin);			return ret;		}		break;	default:		return -EINVAL;	}	return 0;}

    Mind map

    pinctrl
    pinctrl

    Conclusion

    • Conjecture 1

    The first conjecture is that pinctrl pin multiplexing is performed when loading the LED driver. After the device tree of the LED light matches the driver, it enters the probe
    function, and before this, it will executedrivers/base/dd.cin the filereally_probesub-function in the functionpinctrl_bind_pins, this function binds pins for the given device, and during the binding process selects and sets the appropriate pinctrl state. For specific binding details, you can refer to the previous chapters.

    • Conjecture 2

    The second conjecture is that the pin multiplexing is completed when loading the pinctrl driver, because the pinctrl subsystem also conforms to the device model specification and will also execute the corresponding probe function, so similarly, when loading the pinctrl driver, it will also executedrivers/base/dd.cin the filereally_probesub-function in the functionpinctrl_bind_pins, then will the pinctrl pin multiplexing settings be performed at this time? Next, we will conduct an in-depth analysis of this.

    Before the pinctrl probe function is executed, it will callpinctrl_bind_pinsfunction, as can be seen from the preceding content, according to the nesting of functions, the first one to be calledcreate_pinctrlfunction createsstruct pinctrla pin controller of type, and thencreate_pinctrlCallpinctrl_dt_to_mapThe function converts the pin mapping information defined in the device tree intostruct pinctrl_mapstructure, and adds it top->dt_mapsinto the linked list

    123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
    // drivers/pinctrl/devicetree.cint pinctrl_dt_to_map(struct pinctrl *p, struct pinctrl_dev *pctldev){	struct device_node *np = p->dev->of_node;// Get the device tree node of the device associated with the pin controller	int state, ret;	char *propname;	struct property *prop;	const char *statename;	const __be32 *list;	int size, config;	phandle phandle;	struct device_node *np_config;	/* CONFIG_OF enabled, p->dev not instantiated from DT */    	/* If CONFIG_OF is enabled, and p->dev is not instantiated from the device tree */	if (!np) {		if (of_have_populated_dt())			dev_dbg(p->dev,				"no of_node; not parsing pinctrl DT\n");		return 0;	}	/* We may store pointers to property names within the node */    	/* pointer to the property name stored inside the node */	of_node_get(np);//Increase the reference count of the device tree node to ensure that the node will not be released during parsing	/* For each defined state ID */    	/* For each defined state ID */	for (state = 0; ; state++) {		/* Retrieve the pinctrl-* property */        	/* Get the pinctrl-* property */		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 */        	/* Determine whether the pinctrl-names property has named the state */		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.		 */        	/*		 * If not named,then statename it is just an integer state ID。However,,To avoid the trouble of dynamic allocation and later freeing,		 * you can directly statename point to a part of the property name。		 */		if (ret < 0)			statename = prop->name + strlen("pinctrl-");		/* For every referenced pin configuration node in it */        	/* For each referenced pin configuration node in it */		for (config = 0; config < size; config++) {			phandle = be32_to_cpup(list++);			/* Look up the pin configuration node */            		/* Find 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 */            		/* 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 there is no entry in the device tree, generate a dummy state table entry */		if (!size) {			ret = dt_remember_dummy_state(p, statename);			if (ret < 0)				goto err;		}	}	return 0;err:	pinctrl_dt_free_maps(p);	return ret;}

    The key point is: what is passed here is the pinctrl device tree node, and in the for loop at line 32, it will getpinctrl-*property, but there is no such property in the pinctrl node,pinctrl-*The property is added in a series of device nodes, so an error will be returned here, and the same error will be passed up layer by layer to the upper-level functions, eventually causingpinctrl_bind_pins()The function returns an error, so the pin multiplexing cannot be set, that is:

    123
    pinctrl_bind_pins	create_pinctrl		pinctrl_dt_to_map -> 报错

    Therefore, conjecture 2 is incorrect.

    And the probe in Rockchip’s pinctrl driver has such a calling relationship:

    1234567
    rockchip_pinctrl_probe()	rockchip_pinctrl_register()		devm_pinctrl_register()			pinctrl_register()				pinctrl_enable()					pinctrl_claim_hogs()						create_pinctrl()

    From the above calling relationship, it can be seen that the probe function of pinctrl will eventually callcreate_pinctrlto createstruct pinctrltype of pin controller, thereby realizing pinctrl pin multiplexing settings. Similarly, this setting is also unsuccessful,pinctrl_claim_hogsThe function is defined in the kernel source directory underdrivers/pinctrl/core.cthe file

    Loading comments…