📚 技術平臺:嵌入式Jerry(B站)
一、引言
在嵌入式系統中,SoC 芯片的引腳通常具有多種功能,如 GPIO、UART、I2C、SPI 等。為了在不同的應用場景中靈活配置引腳功能,Linux 內核引入了 pinctrl(Pin Control)子系統。該子系統提供了一種統一的機制,用于管理引腳的復用(pin multiplexing)、配置(pin configuration)以及狀態管理。
二、pinctrl 子系統概述
2.1 設計目標
pinctrl 子系統的主要目標包括:
- 引腳復用管理:允許將同一引腳配置為不同的功能,如 GPIO、UART 等。
- 引腳配置管理:設置引腳的電氣屬性,如上拉/下拉、電平驅動能力等。
- 狀態管理:支持根據設備的不同工作狀態(如正常、休眠)切換引腳配置。
2.2 核心組件
pinctrl 子系統的核心組件包括:
- pinctrl_dev:表示一個 pin 控制器設備。
- pinctrl_desc:描述 pin 控制器的結構體,定義了操作接口。
- pinctrl_ops:定義了 pin 控制器的操作函數集。
- pinmux_ops:定義了引腳復用的操作函數集。
- pinconf_ops:定義了引腳配置的操作函數集。
三、設備樹中的 pinctrl 配置
在設備樹中,pinctrl 的配置通常包括以下幾個部分:
3.1 pin 控制器節點
pinctrl: pinctrl@30330000 {compatible = "fsl,imx8mp-iomuxc";reg = <0x30330000 0x10000>;#address-cells = <1>;#size-cells = <0>;
};
3.2 引腳配置節點
pinctrl_uart1: uart1grp {fsl,pins = <MX8MP_IOMUXC_UART1_TXD__UART1_DCE_TX 0x1c4MX8MP_IOMUXC_UART1_RXD__UART1_DCE_RX 0x1c4>;
};
3.3 設備節點引用
&uart1 {pinctrl-names = "default";pinctrl-0 = <&pinctrl_uart1>;status = "okay";
};
四、pinctrl 驅動的實現
以 i.MX8MP 平臺為例,其 pinctrl 驅動位于 drivers/pinctrl/freescale/pinctrl-imx8mp.c
。該驅動主要完成以下任務:
4.1 定義引腳描述
static const struct pinctrl_pin_desc imx8mp_pinctrl_pins[] = {PINCTRL_PIN(0, "GPIO0_IO00"),PINCTRL_PIN(1, "GPIO0_IO01"),// ...
};
4.2 實現操作函數集
static const struct pinctrl_ops imx8mp_pinctrl_ops = {.get_groups_count = imx_pinctrl_get_groups_count,.get_group_name = imx_pinctrl_get_group_name,.get_group_pins = imx_pinctrl_get_group_pins,.dt_node_to_map = imx_pinctrl_dt_node_to_map,.dt_free_map = imx_pinctrl_dt_free_map,
};
4.3 注冊 pin 控制器
static int imx8mp_pinctrl_probe(struct platform_device *pdev)
{return imx_pinctrl_probe(pdev, &imx8mp_pinctrl_data);
}
五、驅動中使用 pinctrl API
在設備驅動中,可以使用以下 API 來獲取和設置引腳狀態:
struct pinctrl *pinctrl;
struct pinctrl_state *state;pinctrl = devm_pinctrl_get(&pdev->dev);
state = pinctrl_lookup_state(pinctrl, "default");
pinctrl_select_state(pinctrl, state);
這些 API 允許驅動在運行時切換引腳的配置狀態,例如在設備進入休眠或喚醒時。
六、實戰案例:配置 UART 引腳
以配置 UART1 的引腳為例,設備樹中的配置如下:
pinctrl_uart1: uart1grp {fsl,pins = <MX8MP_IOMUXC_UART1_TXD__UART1_DCE_TX 0x1c4MX8MP_IOMUXC_UART1_RXD__UART1_DCE_RX 0x1c4>;
};&uart1 {pinctrl-names = "default";pinctrl-0 = <&pinctrl_uart1>;status = "okay";
};
在驅動中,可以使用上述的 pinctrl API 來設置引腳狀態。
七、pinctrl 與 GPIO 子系統的關系
pinctrl 子系統與 GPIO 子系統密切相關。通常,GPIO 控制器是 pin 控制器的一個子集。pinctrl 子系統負責引腳的復用和配置,而 GPIO 子系統負責引腳的輸入輸出操作。
在某些平臺上,pinctrl 驅動需要注冊 GPIO 范圍,以便 GPIO 子系統能夠正確地映射引腳。例如:
static struct pinctrl_gpio_range imx8mp_gpio_ranges[] = {{.name = "gpio1",.id = 0,.base = 0,.pin_base = 0,.npins = 32,.gc = &gpio1_chip,},// ...
};
八、總結
pinctrl 子系統為 Linux 內核提供了一個統一的引腳管理機制,使得驅動開發者可以方便地配置引腳的復用和電氣屬性。通過設備樹的配置和驅動中的 API 調用,pinctrl 子系統簡化了引腳管理的復雜性,提高了驅動的可移植性和可維護性。
技術平臺:嵌入式Jerry