Linux driver development study notes [5]: pinctrl and gpio subsystem

table of Contents

 

table of Contents

1. GPIO usage in Linux

Two, pinctrl subsystem

1. The representation method of pinctrl in the device tree

1.1 IOMUXC SNVS controller

1.2 IOMUXC controller

1.3 gpr controller

1.4 How to add a PIN information

2. pinctrl driver

Three, gpio subsystem

1. The representation method of gpio in the device tree

2. gpio driver

3. gpio subsystem API

4. Of function related to gpio

5. The use process of gpio in the driver


1. GPIO usage in Linux

Two, pinctrl subsystem

1. The representation method of pinctrl in the device tree

1.1 IOMUXC SNVS controller

1.2 IOMUXC controller

1.3 gpr controller

1.4 How to add a PIN information

2. pincrtl driver

Three, gpio subsystem

1. The representation method of gpio in the device tree

2. gpio driver

3. gpio subsystem API

4. Of function related to gpio

5. The use process of gpio in the driver


table of Contents

1. GPIO usage in Linux

Two, pinctrl subsystem

1. The representation method of pinctrl in the device tree

1.1 IOMUXC SNVS controller

1.2 IOMUXC controller

1.3 gpr controller

1.4 How to add a PIN information

2 pincrtl driver

Three, gpio subsystem

1. The representation method of gpio in the device tree

2. gpio driver

3. gpio subsystem API

4. Of function related to gpio

5. The use process of gpio in the driver


1. GPIO usage in Linux

1. Set the multiplexing and electrical properties of PIN through the pinctrl subsystem.

2. Configure and operate GPIO through the gpio subsystem

Two, pinctrl subsystem

Only need to set the relevant attributes of a certain pin in the device tree, other initialization work is done by the pinctrl subsystem, and the source directory of the pinctrl subsystem is drivers/pinctrl . The main work contents of the pinctrl subsystem are as follows:

①. Get pin information in the device tree.

② Set the pin multiplexing function according to the obtained pin information

③. Set the electrical characteristics of the pin according to the acquired pin information, such as up/down, speed, drive capability, etc.

1. The representation method of pinctrl in the device tree

Open imx6ull.dtsi:

1.1 IOMUXC SNVS controller

iomuxc_snvs: iomuxc-snvs@02290000 {
    compatible = "fsl,imx6ull-iomuxc-snvs";
    reg = <0x02290000 0x10000>;
};

1.2 IOMUXC controller

iomuxc: iomuxc@020e0000 {
    compatible = "fsl,imx6ul-iomuxc";
    reg = <0x020e0000 0x4000>;
    pinctrl-names = "default";
    pinctrl-0 = <&pinctrl_hog_1>;
    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 */
                >;
    };
    ………
    }
};

According to the type of device, create the corresponding child node, and then put the PIN used by the device in this node.

1.3 gpr controller

gpr: iomuxc-gpr@020e4000 {
    compatible = "fsl,imx6ul-iomuxc-gpr",
    "fsl,imx6q-iomuxc-gpr", "syscon";
    reg = <0x020e4000 0x4000>;
};

1.4 How to add a PIN information

For the I.MX series SOC, the pinctrl driver obtains the PIN configuration information by reading the "fsl,pins" attribute value. For the pinctrl device tree binding information of the i.MX series SOC, please refer to the binding document Documentation/devicetree/bindings/pinctrl/fsl, imx-pinctrl.txt in the Linux source directory.

pinctrl_hog_1: hoggrp-1 {
    fsl,pins = <
        MX6UL_PAD_UART1_RTS_B__GPIO1_IO19 0x17059 /* SD1 CD */
    >;
};


在imx6ul-pinfunc.h中找到:
#define MX6UL_PAD_UART1_RTS_B__GPIO1_IO19  0x0090  0x031C 0x0000 0x5 0x0


展开后:
pinctrl_hog_1: hoggrp-1 {
    fsl,pins = <
        0x0090 0x031C 0x0000 0x5 0x0 0x17059 /* SD1 CD */
    >;
};
<mux_reg   conf_reg    input_reg    mux_mode    input_val>
 0x0090      0x031C      0x0000       0x5        0x0

1. mux_reg : UART1_RTS_B, the offset address of the PIN multiplex function register. The first address of the parent node of IOMUXC is 0x020e0000, and the address of the multiplex function register of UART1_RTS_B is 0x020e0090,

2. conf_reg : UART1_RTS_B this PIN electrical property register offset address. The electrical property register address of UART1_RTS_B is 0x020e0000+0x031C=0x020e 031C.

3. input_reg , input register offset, 0 means that UART1_RTS_B has no input function.

4. mux_mode : the value of the multiplex function register address, 5 means multiplexed as GPIO1_IO19, write it to 0x020e 0090

5. input_val : is the value written into the input_reg register.

6. 0x17059 : Configure the register value for the electrical properties of the PIN.

2. pinctrl driver

Everything is ready, including register addresses and register values. The corresponding driver file of the Linux kernel will be initialized according to these values. Next, find out which driver file to do this thing. The value of the compatible attribute in the iomuxc node is "fsl,imx6ul-iomuxc". If you search for the string "fsl,imx6ul-iomuxc" globally in the Linux kernel, you will find the corresponding Driver file. The file drivers/pinctrl/freescale/pinctrl-imx6ul.c has the following content:

static struct of_device_id imx6ul_pinctrl_of_match[] = {
	{ .compatible = "fsl,imx6ul-iomuxc", .data = &imx6ul_pinctrl_info, },
	{ .compatible = "fsl,imx6ull-iomuxc-snvs", .data = &imx6ull_snvs_pinctrl_info, },
	{ /* sentinel */ }
};

static int imx6ul_pinctrl_probe(struct platform_device *pdev)
{
	const struct of_device_id *match;
	struct imx_pinctrl_soc_info *pinctrl_info;

	match = of_match_device(imx6ul_pinctrl_of_match, &pdev->dev);

	if (!match)
		return -ENODEV;

	pinctrl_info = (struct imx_pinctrl_soc_info *) match->data;

	return imx_pinctrl_probe(pdev, pinctrl_info);
}

static struct platform_driver imx6ul_pinctrl_driver = {
	.driver = {
		.name = "imx6ul-pinctrl",
		.owner = THIS_MODULE,
		.of_match_table = of_match_ptr(imx6ul_pinctrl_of_match),
	},
	.probe = imx6ul_pinctrl_probe,
	.remove = imx_pinctrl_remove,
};

When the device and the driver match successfully, the function represented by the probe member variable of platform_driver will be executed

Three, gpio subsystem

The pinctrl subsystem focuses on setting the multiplexing and electrical properties of the PIN (some SOCs are called PAD). If the pinctrl subsystem reuses a PIN as a GPIO, then the gpio subsystem will be used next. As the name suggests, the gpio subsystem is used to initialize GPIO and provide corresponding API functions, such as setting GPIO as input and output, reading GPIO value, etc. The main purpose of the gpio subsystem is to facilitate the use of gpio by the driver developer. The driver developer can add gpio-related information in the device tree, and then the API function provided by the gpio subsystem can be used in the driver to operate the GPIO Linux kernel to the driver developer The GPIO setting process is shielded, which greatly facilitates the use of GPIO by driver developers

1. The representation method of gpio in the device tree

Please refer to the document Documentation/devicetree/bindings/gpio/ fsl-imx-gpio.txt for the GPIO controller binding information of the I.MX series SOC

&usdhc1 {
    pinctrl-names = "default", "state_100mhz", "state_200mhz";
    pinctrl-0 = <&pinctrl_usdhc1>;
    pinctrl-1 = <&pinctrl_usdhc1_100mhz>;
    pinctrl-2 = <&pinctrl_usdhc1_200mhz>;
    cd-gpios = <&gpio1 19 GPIO_ACTIVE_LOW>;
    keep-power-in-suspend;
    enable-sdio-wakeup;
    vmmc-supply = <®_sd1_vmmc>;
    status = "okay";
};

A cd-gpios attribute is defined, "&gpio1" means that the IO used by the CD pin belongs to the GPIO1 group, 19 means the 19th IO of the GPIO1 group, and the SD card driver knows that the CD pin uses GPIO1_IO19 through these two values This GPIO. "GPIO_ACTIVE_LOW" means low level is active, if you change GPIO_ACTIVE_HIGH, it means high level is active.

gpio1: gpio@0209c000 {
    compatible = "fsl,imx6ul-gpio", "fsl,imx35-gpio";
    reg = <0x0209c000 0x4000>;
    interrupts = <GIC_SPI 66 IRQ_TYPE_LEVEL_HIGH>,
                 <GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>;
    gpio-controller;
    #gpio-cells = <2>;
    interrupt-controller;
    #interrupt-cells = <2>;
};

2. gpio driver

Search compatible = "fsl, imx6ul-gpio ", "fsl, imx35-gpio", the drivers / gpio / gpio-mxc.c found to match the string, drivers / gpio / gpio-mxc.c is GPIO driver file of i.MX6ULL

static const struct of_device_id mxc_gpio_dt_ids[] = {
	{ .compatible = "fsl,imx1-gpio", .data = &mxc_gpio_devtype[IMX1_GPIO], },
	{ .compatible = "fsl,imx21-gpio", .data = &mxc_gpio_devtype[IMX21_GPIO], },
	{ .compatible = "fsl,imx31-gpio", .data = &mxc_gpio_devtype[IMX31_GPIO], },
	{ .compatible = "fsl,imx35-gpio", .data = &mxc_gpio_devtype[IMX35_GPIO], },
	{ /* sentinel */ }
};

static struct platform_driver mxc_gpio_driver = {
        .driver = {
        .name = "gpio-mxc",
        .of_match_table = mxc_gpio_dt_ids,
	},
	.probe	= mxc_gpio_probe,
	.id_table = mxc_gpio_devtype,
};

It can be seen that the GPIO driver is also a platform device driver, so when the device node in the device tree matches the driver's of_device_id, the probe function will be executed. The implementation process is similar to pinctl

3. gpio subsystem API

(1)int gpio_request(unsigned gpio, const char *label)

The gpio_request function is used to apply for a GPIO pin, you must use gpio_request to apply before using a GPIO

gpio: the gpio label to be applied for, use the of_get_named_gpio function to get the specified GPIO attribute information from the device tree, this function will return the GPIO label.

label: Set a name for gpio.

Return value: 0, the application was successful; other values, the application failed.

(2)void gpio_free(unsigned gpio)

If you do not use a GPIO, then you can call gpio_free function to release

gpio: the gpio label to be released

(3)int gpio_direction_input(unsigned gpio)

This function is used to set a GPIO as input

gpio: GPIO label to be set as input.

Return value: 0, set successfully; negative value, set failed.

(4)int gpio_direction_output(unsigned gpio, int value)

This function is used to set a GPIO as output and set the default output value

gpio: GPIO label to be set as output.

value GPIO default output value.

Return value: 0, set successfully; negative value, set failed.

(5)#define gpio_get_value int __gpio_get_value(unsigned gpio)

This function is used to get the value of a GPIO (0 or 1)

(6)#define gpio_set_value void __gpio_set_value(unsigned gpio, int value)

This function is used to set the value of a GPIO

4. Of function related to gpio

(1)int of_gpio_named_count(struct device_node *np, const char *propname)

(2)int of_gpio_count(struct device_node *np)

(3)int of_get_named_gpio(struct device_node *np, const char *propname, int index)

5. The use process of gpio in the driver

1. First, get the device node where the GPIO is located, such as of_find_node_by_path.

2. Get the GPIO number, of_get_named_gpio function, the return value is the GPIO number.

3. Request the GPIO of this number, gpio_request function

4. Set GPIO, input or output, gpio_direction_input or gpio_direction_output.

5. If it is input, read the GPIO value through the gpio_get_value function, if it is output, set the GPIO value through gpio_set_value.

 

 

 

Guess you like

Origin blog.csdn.net/m0_37845735/article/details/106977195