Linux 驱动讲究驱动分离与分层,也就是把与soc芯片相关的一些驱动代码与具体的驱动应用给分离开。
pinctrl子系统
pinctrl 子系统主要完成:①获取设备树中 pin 信息②根据获取到的 pin 信息来设置 pin 的复用功能③根据获取到的 pin 信息来设置 pin 的电气特性,比如上/下拉、速度、驱动能力等。
也即是说我们只需要在设备树中描述好这个gpio的具体属性,则pinctrl子系统会根据这些信息帮我们初始化好这个pin。
pinctrl在设备树中的添加/修改方法
我们打开设备树文件imx6ull-alientek-emmc.dts。找到iomuxc节点。在iomuxc节点下创建一个子结点,内容如下:
pinctrl_led: ledgrp{
fsl,pins = <
MX6UL_PAD_GPIO1_IO03__GPIO1_IO03 0x10B0
>;
};
- pinctrl节点的节点名称必须是以pincrtl_xxxx来命名
- pinctrl 驱动程序是通过读取“fsl,pins”属性值来获取 PIN 的配置信息
- fsl中填写的是PIN的复用功能,pins中填写的是PIN的电气属性。
MX6UL_PAD_UART1_RTS_B__GPIO1_IO19,这是一个宏定义,定义在文件arch/arm/boot/dts/imx6ul-pinfunc.h。打开这个文件我们可以看到里面有好多个宏。
这些宏其实是5个一组的值。具体含义就是<mux_reg conf_reg input_reg mux_mode input_val> - mux_reg:mux_reg 寄存器偏移地址
- conf_reg:conf_reg 寄存器偏移地址
- input_reg:input_reg 寄存器偏移地址
- mux_reg:mux_reg寄存器值
- input_val:input_reg 寄存器值
- 另外:pins中填写的就是conf_reg 寄存器的值
那么有个问题,iomux如何根据这些信息来初始化pin。
iomuxc 节点中 compatible 属性的值为“fsl,imx6ul-iomuxc”,在 Linux 内核中全局搜索“fsl,imx6ul-iomuxc”字符串就会找到对应的驱动文件
第326行有一个 of_device_id 结构体数组,保存着这个驱动文件的兼容性值。那也就说 pinctrl-imx6ul.c 会完成 I.MX6ULL 的 PIN 配置工作。
第347-355行有一个platform_driver结构体类型变量。它里面有个 probe 成员变量,当设备和驱动匹配成功以后 platform_driver 的 probe 成员变量所代表的函数就会执行。也就是说imx6ul_pinctrl_probe是PIN配置的入口函数。
调用路径如下:
imx_pinctrl_parse_groups 负责获取设备树中关于 PIN 的配置信息。
pinctrl_register此函数用于向Linux内核注册一个PIN控制器,函数原型如下
余下的没有深究
gpio子系统
gpio子系统用于初始化 GPIO 并且提供相应的 API 函数,比如设置 GPIO为输入输出,读取 GPIO 的值等。
驱动开发者在设备树中添加 gpio 相关信息,然后就可以在驱动程序中使用 gpio 子系统提供的 API函数来操作 GPIO
我们在设备树根节点添加gpioled节点
gpioled{
#address-cells = <1>;
#size-cells = <1>;
compatible = "atkalpha-gpioled";
pinctrl-name = "default";
pinctrl-0 = <&pinctrl_led>; //指定使用的PIN对应的pinctrl节点
led-gpio = <&gpio1 3 GPIO_ACTIVE_LOW>;//指定所使用的GPIO为GPIO1-IO03且低电平有效
status = "okay";
};
gpio子系统API函数
gpio_request函数,申请一个GPIO管脚
//要申请的 gpio 标号 //给 gpio 设置个名字 int gpio_request(unsigned gpio, const char *label)
gpio_free函数,释放一个GPIO管脚
//要释放的 gpio 标号 void gpio_free(unsigned gpio)
gpio_direction_input函数
//设置某个 GPIO 为输入 int gpio_direction_input(unsigned gpio)
gpio_direction_output函数
//要设置为输出的 GPIO 标号 //GPIO 默认输出值 int gpio_direction_output(unsigned gpio, int value)
gpio_get_value函数
//要获取的 GPIO 标号 int __gpio_get_value(unsigned gpio)
gpio_set_value函数
//gpio:要设置的 GPIO 标号 //value: 要设置的值 __gpio_set_value(unsigned gpio, int value)
与gpio相关的of函数
1.of_gpio_named_count 函数(获取设备树某个属性里面定义了几个 GPIO 信息,包括空信息)
//np:设备节点 //propname:要统计的 GPIO 属性 int of_gpio_named_count(struct device_node *np, const char *propname)
2.of_gpio_count函数(获取设备树“gpios”这个属性的 GPIO 数量,包括空信息)
//np:设备节点 int of_gpio_count(struct device_node *np)
3.of_get_named_gpio(获取 GPIO 编号)
//np:设备节点 //propname:包含要获取 GPIO 信息的属性名 //GPIO 索引(因为一个属性里面可能包含多个 GPIO,此参数指定要获取哪个 GPIO的编号,如果只有一个 GPIO 信息的话此参数为 0。) int of_get_named_gpio(struct device_node *np,const char *propname,int index) /*补充:此函数在驱动中使用很频繁*/
评论 (0)