Detailed explanation of the pinctrl subsystem driver framework of the Linux kernel

Table of contents

1 introduction

2 pinctrl in device tree

2.1 iomuxc node

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_drvdataipctlpdevplatform_get_drvdataipctl

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 

Guess you like

Origin blog.csdn.net/u013171226/article/details/132431972