Table of contents
2.2 How to use the pinctrl controller for other nodes
3 pin controller code flow and related data structures
4 device client code process and related data structures
5 Related questions when reading the kernel source code
6 Feynman Learning Method: So I recorded a video explaining the pinctrl subsystem
1 introduction
Regardless of STM32 or IMX6ULL, if we want to use a certain pin to control the on and off of the LED light, then generally speaking we need to configure the pin as shown in the figure above. The function and electrical properties of the pin are configured in the Linux kernel: This is done by the pinctrl subsystem. The pinctrl subsystem has three main functions:
- Function 1: Enumeration and naming of pins
- Function 2: Pin multiplexing (Multiplexing)
- Function 3: Set electrical properties (Configuration)
In addition, the code related to the pinctrl subsystem in the Linux kernel has been implemented by chip manufacturers. Users do not need to write code, they only need to modify the device tree file.
2 pinctrl in device tree
Different manufacturers have different pinctrl device tree formats. Here we take the imx6ull platform as an example. The following code reading is based on the Linux4.9.88 kernel source code provided by imx6ull as an example for reading and explanation.
2.1 iomuxc node
First look at the iomuxc node
iomuxc: iomuxc@020e0000 {
compatible = "fsl,imx6ul-iomuxc";
reg = <0x020e0000 0x4000>;
imx6ul-evk {
pinctrl_hog_1: hoggrp-1 {
fsl,pins = <
MX6UL_PAD_UART1_RTS_B__GPIO1_IO19 0x17059 /* SD1 CD */
MX6UL_PAD_GPIO1_IO05__USDHC1_VSELECT 0x17059 /* SD1 VSELECT */
MX6UL_PAD_GPIO1_IO09__GPIO1_IO09 0x17059 /* SD1 RESET */
>;
};
pinctrl_csi1: csi1grp {
fsl,pins = <
MX6UL_PAD_CSI_MCLK__CSI_MCLK 0x1b088
MX6UL_PAD_CSI_PIXCLK__CSI_PIXCLK 0x1b088
...没写全...
MX6UL_PAD_CSI_DATA06__CSI_DATA08 0x1b088
MX6UL_PAD_CSI_DATA07__CSI_DATA09 0x1b088
>;
};
pinctrl_i2c1: i2c1grp {
fsl,pins = <
MX6UL_PAD_UART4_TX_DATA__I2C1_SCL 0x4001b8b0
MX6UL_PAD_UART4_RX_DATA__I2C1_SDA 0x4001b8b0
>;
};
}
};
The information in fsl and pins is the offset address and value of the register, which is used to configure the multiplexing and electrical properties of a certain pin, such as taking as an example
MX6UL_PAD_UART1_RTS_B__GPIO1_IO19 0x17059 /* SD1 CD */
Where MX6UL_PAD_UART1_RTS_B__GPIO1_IO19 is a macro definition,
#define MX6UL_PAD_UART1_RTS_B__GPIO1_IO19 0x0090 0x031c 0x0000 5 0
If you replace the macro definition, then MX6UL_PAD_UART1_RTS_B__GPIO1_IO19 0x17059 /* SD1 CD */ is
0x0090 0x031c 0x0000 5 0 0x17059
These six values are
mux_reg conf_reg input_reg mux_mode input_val conf_reg
According to these 6 values, the multiplexing and electrical properties of a pin can be configured.
2.2 How to use the pinctrl controller for other nodes
For example i2c1
&i2c1 {
clock-frequency = <100000>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_i2c1>;
status = "okay";};
In this way, the i2c1 node uses the pin configuration provided by pinctrl.
At this point, we can actually finish talking about the pinctrl subsystem, because it can be used. The following explanation is for understanding, and then I read the Linux kernel source code.
3 pin controller code flow and related data structures
I directly drew a picture to explain the code flow and related data structure of the pin controller.
First, the iomuxc node in the device tree will be converted into a platform_device, and then when matching according to compatible = "fsl,imx6ul-iomuxc", the imx6ul_pinctrl_probe function will be called. In this function, pinctrl_info = (struct imx_pinctrl_soc_info *) is first taken out match->data; This is actually an enumeration of pins, and then the imx_pinctrl_probe(pdev, pinctrl_info); function is called. A pinctrl_desc structure is allocated in this function.
imx_pinctrl_desc->name = dev_name(&pdev->dev);
imx_pinctrl_desc->pins = info->pins;
imx_pinctrl_desc->npins = info->npins;
imx_pinctrl_desc->pctlops = &imx_pctrl_ops;
imx_pinctrl_desc->pmxops = &imx_pmx_ops;
imx_pinctrl_desc->confops = &imx_pinconf_ops;
imx_pinctrl_desc->owner = THIS_MODULE;
Then this structure contains pins and some operation functions, and then calls imx_pinctrl_probe_dt(pdev, info); here the device tree is parsed to get those register addresses and register values. Then call the ipctl->pctl = devm_pinctrl_register(&pdev->dev, imx_pinctrl_desc, ipctl); function. This function constructs a struct pinctrl_dev *pctldev; structure. This struct pinctrl_dev *pctldev; structure contains pins and operation functions. , as well as all information such as register values and register addresses.
4 device client code process and related data structures
First, let’s take a look at the data structure of the device client. I drew a diagram to represent it.
Then let's take a look at the Linux kernel source code and see the construction process of the above data structures. I also drew a picture directly.
5 Related questions when reading the kernel source code
Hello! Your understanding is correct. In this code, the function is platform_set_drvdata(pdev, ipctl);
called to associate with the platform device . In this way, when you need to access the private data of the device in the device driver, you can use the function to obtain it .platform_set_drvdata
ipctl
pdev
platform_get_drvdata
ipctl
ipctl
Is a imx_pinctrl
pointer to a structure that contains the pin register information parsed from the device tree. These information are stored in ipctl->info->pin_regs
an array, and each element is a imx_pin_reg
structure, which represents the register information of a pin.
Therefore, in this code, the pin register information parsed from the device tree is saved in pdev->dev.driver_data
. Hope this information helps you!
6 Feynman Learning Method: So I recorded a video explaining the pinctrl subsystem
A 15-minute explanation of the pinctrl subsystem of the Linux kernel_bilibili_bilibili