1.引脚控制
最古老也是最普世的引脚控制方法:操作引脚寄存器
1.1 pinctrl子系统
- 配置引脚功能用于UART、SPI、I2C、GPIO等
- 提供接口配置中断
- 使用设备树定义
举例&iomux下有子节点
pinctrl_keys: keysgrp {
fsl,pins = <
MX6ULL_PAD_SNVS_TAMPER4__GPIO5_IO04 0x80000000
MX6ULL_PAD_SNVS_TAMPER2__GPIO5_IO02 0x80000000
MX6ULL_PAD_SNVS_TAMPER9__GPIO5_IO09 0x80000000
>;
};
pin controller没有统一的格式,在i.MX6ULL中应作如上形式配置。此节点记录了将哪个引脚复用为何种功能并做什么配置,即“引脚-功能-配置”的对应。
引用pin controller结点的结点称为client device,例如根节点下方可以有如下子节点
gpio-keys {
compatible = "gpio-keys";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_keys>;
#address-cells = <1>;
#size-cells = <0>;
autorepeat;
其中pinctrl-name
只有一个值,表示这个设备只有一种状态,即default
,对应pinctrl-0
,其引用了pinctrl_keys
结点。即当设备处于此状态时,引脚将被复用为彼功能。
问题:驱动如何选择状态?
1.2 GPIO子系统
提供API操作GPIO引脚如
gpio_request():请求一个GPIO引脚并进行相关的配置,使其可用于驱动程序的操作;
gpio_free():释放之前请求的GPIO引脚,将其解除分配并释放资源;
gpio_direction_input():将指定的GPIO引脚配置为输入模式;
gpio_direction_output():将指定的GPIO引脚配置为输出模式;
gpio_get_value():获取指定GPIO引脚的当前输入值;
gpio_set_value():设置指定GPIO引脚的输出值;
gpio_cansleep():检查指定的GPIO引脚是否支持睡眠(sleep)操作;
gpio_to_desc():根据GPIO引脚的编号获取对应的GPIO描述符;
这些函数通常定义在<linxu/gpio.h>头文件中,使用时需要包含该头文件。编写驱动时会使用这些函数。
2.LED驱动适配
2.1 修改设备树
打开arch/arm/boot/dts/imx6ul-pinfunc.h找到需要引脚宏定义。
gedit arch/arm/boot/dts/imx6ul-pinfunc.h
imx6ul-pinfunc.h存放imx6ul和imx6ull通用内容,引脚复用通过&iomuxc结点修改
imx6ull-pinfunc-snvs.h存放imx6ull独有内容,引脚复用通过&iomuxc_snvs结点修改
搜索欲要复用的引脚,有
#define MX6UL_PAD_JTAG_MOD__GPIO1_IO10 0x0044 0x02D0 0x0000 0x5 0x0
#define MX6UL_PAD_UART1_CTS_B__GPIO1_IO18 0x008C 0x0318 0x0000 0x5 0x0
#define MX6UL_PAD_GPIO1_IO00__GPIO1_IO00 0x005C 0x02E8 0x0000 0x5 0x0
打开设备树文件
gedit arch/arm/boot/dts/imx6ull-elf1-emmc.dts
在&iomuxc 节点下添 加子节点pinctrl_leds0
pinctrl_leds0:leds0grp {
fsl,pins = <
MX6UL_PAD_UART1_CTS_B__GPIO1_IO18 0x10b0
MX6UL_PAD_JTAG_MOD__GPIO1_IO10 0x10b0
MX6UL_PAD_GPIO1_IO00__GPIO1_IO00 0x10b0
>;
};
在根节点下方添加leds子节点
leds {
compatible = "gpio-leds"; //驱动匹配
pinctrl-names = "default"; //pinctrl名字
pinctrl-0 = <&pinctrl_leds0 >; //对IOMUX配置进行引用
status = "okay"; //设备可用
led1{
lable = "led1"; //可有可无
gpios = <&gpio1 10 GPIO_ACTIVE_LOW>; //指定并配置引脚 ACTIVE_LOW:低电平点亮
default-state = "off"; //默认状态
};
led2{
lable = "led2";
gpios = <&gpio1 0 GPIO_ACTIVE_LOW>;
default-state = "on";
};
led3{
lable = "led3";
gpios = <&gpio1 18 GPIO_ACTIVE_LOW>;
default-state = "on";
};
2.2 编译驱动进内核
编译配置文件后使用make menuconfig命令
make imx6ull_elf1_defconfig
make menuconfig
搜索LEDS_GPIO,若有[=y]则表示该驱动已被选择编译进内核。编译内核与设备树。
./build.sh
拷贝内核与设备树
scp arch/arm/boot/zImage root@\192.168.0.232:/run/media/mmcblk1p1/
scp arch/arm/boot/dts/imx6ull-elf1\-emmc.dtb root@192.168.0.232:/run/media/mmcblk1p1/
开发板输入指令
sync
reboot
2.3 测试
测试指令
echo 1 > /sys/class/leds/led1/brightness
echo 0 > /sys/class/leds/led1/brightness
echo heartbeat > /sys/class/leds/led1/trigger
echo none > /sys/class/leds/led1/trigger
作用依次为:LED1亮、LED1灭、LED1心跳闪烁、关闭LED1触发器
3.按键驱动适配
使用Linux系统中集成的gpio-key驱动
开发板按键资源
key1->GPIO5_4(22脚)
key2->GPIO5_2(34脚)
key3->GPIO5_9(43脚)
平时为高电平,触发后为低电平
3.1 修改设备结点
复用按键引脚为GPIO功能
宏定义位于arch/arm/boot/dts/imx6ull-pinfunc-snvs.h
在设备树文件arch/arm/boot/dts/imx6ull-elf1-emmc.dts
中的&iomux_snvs结点下添加子节点pinctrl_keys
pinctrl_keys: keysgrp {
fsl,pins = <
MX6ULL_PAD_SNVS_TAMPER4__GPIO5_IO04 0x80000000
MX6ULL_PAD_SNVS_TAMPER2__GPIO5_IO02 0x80000000
MX6ULL_PAD_SNVS_TAMPER9__GPIO5_IO09 0x80000000
>;
};
在根节点下方添加设备结点
gpio-keys {
compatible = "gpio-keys";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_keys>;
#address-cells = <1>;
#size-cells = <0>;
autorepeat;
key1 {
label = "KEY1";
linux,code = <KEY_ENTER>;
gpios = <&gpio5 4 GPIO_ACTIVE_LOW>;
};
key2 {
label = "KEY2";
linux,code= <KEY_UP>;
gpios = <&gpio5 2 GPIO_ACTIVE_LOW>;
};
key3 {
label = "KEY3";
linux,code = <KEY_DOWN>;
gpios = <&gpio5 9 GPIO_ACTIVE_LOW>;
};
};
gpios属性值指定了具体的GPIO引脚以及引脚的极性配置
在include/dt-bindings/input/input.h可查看按键定义的键值
d#efine KEY_ENTER 28
#define KEY_UP 103
#define KEY_DOWN 108
3.2 编译驱动
检查驱动是否编辑进内核
make menuconfig
驱动路径:Device Drivers->Input device support->Keyboards
为减少编译时间,可用“#”注释build.sh文件中的make distclean
编译并拷贝内核及设备树
./build.sh
scp arch/arm/boot/zImage root@\192.168.0.232:/run/media/mmcblk1p1/
scp arch/arm/boot/dts/imx6ull-elf1\-emmc.dtb root@192.168.0.232:/run/media/mmcblk1p1/
重启开发板
sync
reboot
3.3 测试
查看key所对应事,输入事件测试指定并选择对应事件。
cat /proc/bus/input/devices
evtest