Openwrt MT7628/MT7620/MT7621——GPIO及LED/KEY的功能实现
GPIO及LED/KEY的功能实现
流程介绍
GPIO功能注册和控制
MT7628支持引脚功能的复用,通过配置GPIO1_MODE和GPIO2_MODE寄存器可指定引脚的功能,通常在dts文件中对引脚功能进行注册。
MT7628引脚的GPIO注册位于/target/linux/ramips/dts/mt7628an.dtsi文件中,GPIO总共被分为3组,gpio0(GPIO#0——GPIO#31)、gpio1(GPIO#32——GPIO#63)和gpio2(GPIO#64——GPIO#95), @指明了gpio寄存器的起始地址为0x600,节点中compatible属性值指定了设备使用驱动为 mtk,mt7621-gpio。
aaa@qq.com {
#address-cells = <1>;
#size-cells = <0>;
compatible = "mtk,mt7628-gpio", "mtk,mt7621-gpio";
reg = <0x600 0x100>;
interrupt-parent = <&intc>;
interrupts = <6>;
gpio0: aaa@qq.com {
reg = <0>;
compatible = "mtk,mt7621-gpio-bank";
gpio-controller;
#gpio-cells = <2>;
};
gpio1: aaa@qq.com {
reg = <1>;
compatible = "mtk,mt7621-gpio-bank";
gpio-controller;
#gpio-cells = <2>;
};
gpio2: aaa@qq.com {
reg = <2>;
compatible = "mtk,mt7621-gpio-bank";
gpio-controller;
#gpio-cells = <2>;
};
};
使用GPIO引脚除了注册GPIO外,还需要释放GPIO引脚复用功能,将功能名称添加至 ralink group 属性中:
&pinctrl {
state_default: pinctrl0 {
gpio {
ralink,group = "i2c", "gpio", "jtag", "i2s", "spi cs1", "uart2", "pwm0", "pwm1", "sdmode", "spis";
ralink,function = "gpio";
};
};
与dts文件对应的引脚复用定义在source-17.01.4/build_dir/target-mipsel_24kc_musl-1.1.16/linux-ramips_mt7628/linux-4.4.92/arch/mips/ralink/mt7620.c中。
如以下代码中i2c复用的gpio引脚定义为gpio#1和gpio#2(从gpio#1开始占用2个gpio), spi refclk复用的gpio引脚定义为gpio#37、gpio#38、gpio#39。同理,其他复用引脚的定义一样。
static struct rt2880_pmx_func i2c_grp[] = { FUNC("i2c", 0, 1, 2) };
static struct rt2880_pmx_func spi_grp[] = { FUNC("spi", 0, 3, 4) };
static struct rt2880_pmx_func uartlite_grp[] = { FUNC("uartlite", 0, 15, 2) };
static struct rt2880_pmx_func rgmii1_grp[] = { FUNC("rgmii1", 0, 24, 12) };
static struct rt2880_pmx_func refclk_grp[] = { FUNC("spi refclk", 0, 37, 3) };
如以下代码中与WRTNODE2P.dts中ralink group属性的GPIO复用功能相对应。
static struct rt2880_pmx_group mt7628an_pinmux_data[] = {
……
GRP_G("i2c", i2c_grp_mt7628, MT7628_GPIO_MODE_MASK,
1, MT7628_GPIO_MODE_I2C),
GRP("refclk", refclk_grp_mt7628, 1, MT7628_GPIO_MODE_REFCLK),
GRP("perst", perst_grp_mt7628, 1, MT7628_GPIO_MODE_PERST),
GRP("wdt", wdt_grp_mt7628, 1, MT7628_GPIO_MODE_WDT),
GRP("spi", spi_grp_mt7628, 1, MT7628_GPIO_MODE_SPI),
GRP_G("sdmode", sd_mode_grp_mt7628, MT7628_GPIO_MODE_MASK,
1, MT7628_GPIO_MODE_SDMODE),
GRP_G("uart0", uart0_grp_mt7628, MT7628_GPIO_MODE_MASK,
1, MT7628_GPIO_MODE_UART0),
……
{ 0 }
};
用户可以通过sysfs接口方式访问GPIO(目录位于/sys/class/gpio),gpio目录中包括 export文件、 unexport文件、gpiochipx目录、gpiox目录。
/sys/class/export文件用于通过GPIO引脚编号导出控制的gpio文件,/sys/class/unexport文件用于通过GPIO引脚编号去除控制的gpio文件。export导出成功后会在目录中生成/sys/class/gpio/gpiox目录,如果未出现相应的目录,说明该引脚不可导出。
/sys/class/gpiochipx/目录用于管理和控制一组GPIO的控制器, 目录保存该组GPIO寄存器信息,如寄存器控制引脚的起始编号base、寄存器名称label、引脚总数ngpio。
/sys/class/gpiox/目录用于具体的GPIO引脚控制,目录下有 direction、 value、edge等属性文件。其中direction文件定义为GPIO引脚方向(out为输出、in为输入)。value文件定义为GPIO引脚的电平(0为低电平,1为高电平), 当GPIO引脚方向配置为输出时,value文件值可写(任何非零的值都将输出高电平),当GPIO引脚方向配置为输入时,value文件值可读(cat value)。edge定义为中断的触发方式。
GPIO-LED功能注册和控制
在将GPIO注册为LED设备之前需要在配置界面(make menuconfig命令进入配置界面)选择添加Led驱动(默认编译时已经选上)
Led驱动: > Kernel modules > LED modules > <*> kmod-leds-gpio
WRTNODE2P.dts文件中将GPIO注册为LED设备,compatible属性值与LED驱动文件leds-gpio.c中的compatible属性值相对应。label值最终对应为文件系统/sys/class/leds/目录下LED设备的名称。
gpio-leds {
compatible = "gpio-leds";
indicator {
label = "wrtnode:blue:indicator";
gpios = <&gpio1 9 1>;
};
gpio35 {
label = "wrtnode:red:sys_status";
gpios = <&gpio1 12 1>;
};
gpio3 {
label = "wrtnode:yellow:3g_wwan1";
gpios = <&gpio0 3 1>;
};
};
烧录固件后进入 /sys/class/leds 可查看注册成功的led设备,可通过对brightness文件写入1和0的方式控制LED亮灭。
GPIO-KEY功能注册和控制
将GPIO注册为KEY设备与LED的方法类似,需要在配置界面(make menuconfig命令进入配置界面)选择添加Button的驱动(默认编译时已经选上)
Button 驱动: > Kernel modules > Other modules > kmod-gpio-button-hotplug
同理WRTNODE2P.dts文件中将GPIO#5注册为名为"reset"的KEY,通过调试状态查看KEY值,hi 表示高电平,lo 表示低电平。
gpio-keys-polled {
compatible = "gpio-keys-polled";
#address-cells = <1>;
#size-cells = <0>;
poll-interval = <20>;
reset {
label = "reset";
gpios = <&gpio0 5 1>;
linux,code = <KEY_RESTART>;
};
};
按键驱动文件 package/kernel/gpio-button-hotplug/src/gpio-button-hotplug.c中对按键的键值和名称进行了映射,比如"reset"按键,键值为 KEY_RESTART,当按下或释放该按键时驱动会向用户层发送事件执行/etc/rc.button/目录下所对应的脚本 reset.
static struct bh_map button_map[] = {
BH_MAP(BTN_0, "BTN_0"),
BH_MAP(BTN_1, "BTN_1"),
BH_MAP(BTN_2, "BTN_2"),
BH_MAP(BTN_3, "BTN_3"),
BH_MAP(BTN_4, "BTN_4"),
BH_MAP(BTN_5, "BTN_5"),
BH_MAP(BTN_6, "BTN_6"),
BH_MAP(BTN_7, "BTN_7"),
BH_MAP(BTN_8, "BTN_8"),
BH_MAP(BTN_9, "BTN_9"),
BH_MAP(KEY_BRIGHTNESS_ZERO, "brightness_zero"),
BH_MAP(KEY_CONFIG, "config"),
BH_MAP(KEY_COPY, "copy"),
BH_MAP(KEY_EJECTCD, "eject"),
BH_MAP(KEY_HELP, "help"),
BH_MAP(KEY_LIGHTS_TOGGLE, "lights_toggle"),
BH_MAP(KEY_PHONE, "phone"),
BH_MAP(KEY_POWER, "power"),
BH_MAP(KEY_RESTART, "reset"),
BH_MAP(KEY_RFKILL, "rfkill"),
BH_MAP(KEY_VIDEO, "video"),
BH_MAP(KEY_WIMAX, "wwan"),
BH_MAP(KEY_WLAN, "wlan"),
BH_MAP(KEY_WPS_BUTTON, "wps"),
};
例子代码
1.dts文件需要引入头文件
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/input/input.h>
2.dts文件配置reset功能 32+6=38 对应GPIO38
gpio-keys {
compatible = "gpio-keys-polled";
poll-interval = <20>;
reset {
label = "reset";
gpios = <&gpio1 6 GPIO_ACTIVE_LOW>;
linux,code = <KEY_RESTART>;
};
};
3. 修改/etc/rc.button/reset脚本
. /lib/functions.sh
OVERLAY="$( grep ' /overlay ' /proc/mounts )"
case "$ACTION" in
pressed)
[ -z "$OVERLAY" ] && return 0
return 5
;;
timeout)
. /etc/diag.sh
set_state failsafe
;;
released)
if [ "$SEEN" -ge 3 -a "$SEEN" -lt 8 ]
then
echo "REBOOT" > /dev/console
sync
reboot
elif [ "$SEEN" -ge 10 -a -n "$OVERLAY" ]
then
echo "FACTORY RESET" > /dev/console
jffs2reset -y && reboot &
fi
;;
esac
参考链接
上一篇: 关于用opencv 设置摄像头读分辨率问题的若干说明
下一篇: C#结合SMTP实现邮件报警通知